Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "baton",
"displayName": "Baton",
"version": "1.4.1",
"version": "1.5.0-rc.1",
"description": "Pass the baton. Conduct the fleet. Claude Code as command-and-control for a fleet of coding LLMs — capability routing, cost engine, jobs, decisions, and a knowledge base.",
"author": { "name": "Kevin Rank", "url": "https://github.com/Ryfter" },
"repository": "https://github.com/Ryfter/baton",
Expand Down
13 changes: 13 additions & 0 deletions commands/init.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
description: Alias for /baton:start — the front porch. See /baton:start for the full procedure.
argument-hint: ["<name>"] [--folder <path>] [--goal "<text>"] [--budget <n>] [--max-tier local|free|paid] [--depth light|adaptive|full] [--quiet]
---

# /baton:init

This is an alias for `/baton:start`. Execute the exact procedure documented in
`commands/start.md`, passing `$ARGUMENTS` through unchanged.

## Arguments

$ARGUMENTS
13 changes: 13 additions & 0 deletions commands/initialize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
description: Alias for /baton:start — the front porch. See /baton:start for the full procedure.
argument-hint: ["<name>"] [--folder <path>] [--goal "<text>"] [--budget <n>] [--max-tier local|free|paid] [--depth light|adaptive|full] [--quiet]
---

# /baton:initialize

This is an alias for `/baton:start`. Execute the exact procedure documented in
`commands/start.md`, passing `$ARGUMENTS` through unchanged.

## Arguments

$ARGUMENTS
173 changes: 173 additions & 0 deletions commands/start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
---
description: The front porch — start a new project or resume one, guided in plain language, then run it full-auto via /baton:go. Aliases: /baton:init, /baton:initialize.
argument-hint: ["<name>"] [--folder <path>] [--goal "<text>"] [--budget <n>] [--max-tier local|free|paid] [--depth light|adaptive|full] [--quiet]
---

# /baton:start

You are the **Front Porch**. This is the one command someone types to begin or
resume a project — including someone who does not know what git is or how to
code. Your job: figure out what they want (in plain language, at a depth that
fits them), set up the mechanics *for* them while explaining each step, write
down their reasoning, then drive `/baton:go` full-auto and tell them what
happens next, and why.

## Steps

1. **Parse `$ARGUMENTS`.** Optional leading quoted **name**. Flags:
`--folder <path>`, `--goal "<text>"`, `--budget <n>`,
`--max-tier local|free|paid`, `--depth light|adaptive|full`, `--quiet`
(forces teaching level to `quiet`). Anything not supplied is asked for (new
path) or inferred (resume path).

2. **Resolve the project + load state:**

```powershell
. "$HOME/.claude/scripts/job-lib.ps1"
. "$HOME/.claude/scripts/start-lib.ps1"

$name = '<NAME_OR_EMPTY>'
$folderFlag = '<FOLDER_FLAG_OR_EMPTY>'
$targetFolder = if ($folderFlag) { $folderFlag } else { (Get-Location).Path }

$projectId = if ($name) { ConvertTo-JobSlug $name } else { Resolve-ProjectId -Override $null }
$projRecord = Read-ProjectRecord -ProjectId $projectId
$profile = Read-UserProfile
$mode = Resolve-StartMode -ProjectRecord $projRecord
$teachLevel = Resolve-TeachingLevel -Profile $profile -Explicit '<QUIET_FLAG_OR_EMPTY>'
```

3. **Resume path** (`$mode -eq 'resume'`):
- Print `Format-ResumeStatus -ProjectRecord $projRecord` in plain language.
- Compute `Get-NextCommandRecommendation -RunStatus $projRecord.last_run.status`
(skip if `last_run` is `$null`) and surface it — in `teach` mode, include the
`why`; in `quiet` mode, just the `command`.
- Ask: *"Resume with a new outcome, or pick up the recommended next step?"*
Wait for the answer, then either go to step 6 with a new goal, or hand off
to the recommended command directly (do not re-run onboarding).

4. **New path onboarding** (`$mode -eq 'new'`):
- `$depth = Resolve-InterviewDepth -Profile $profile -Explicit '<DEPTH_FLAG_OR_EMPTY>'`
- Run the guided interview at that depth (always in plain language, never
assuming the user knows jargon):
- **All depths:** if no name was supplied as the leading CLI argument in
step 1 (`$name` is empty), ask "What should we call this project?" as
part of the interview → `$name`. If the user has no preference, fall
back to a sensible default — the title-cased leaf folder name of
`$targetFolder` once resolved below (e.g. `acme-api` → `Acme Api`), or a
title-cased version of `$projectId` if the folder name isn't usable —
and confirm the chosen default back to them. Either way, `$name` must be
a non-empty string before step 6 runs.
- **All depths:** "What are you trying to make?" → `$goal`. If `--goal` was
already supplied on the command line, skip asking and confirm it back to
the user instead.
- **`adaptive` and `full`:** also ask "Who is it for?" → `$audience`, and
"How will we know it's working, or done?" → `$done`.
- **`light`:** skip audience/done unless the user volunteers them; still
offer a proactive suggestion if the goal is vague (e.g. "Want me to also
ask who this is for, or just dive in?").
- **All depths:** ask "Where should this live?" → `$targetFolder` (default
to the flag/cwd from step 2 if the user has no preference; if they have
no idea at all, recommend a sensible default under a projects directory
and explain why).
- Capture the user's own words on *why* they want this as `$reasoning` —
this is the CHARTER's "Why" section; do not paraphrase away specifics.

5. **Folder — detect & branch, narrated (`teach` mode explains each line):**
- If `$targetFolder` exists and is already a git repo → adopt it as-is.
- If it exists and is **not** a git repo → explain ("git saves snapshots of
your work so nothing is ever lost, and lets us go back a step if needed"),
then `git init` inside it.
- If it does not exist → create it, `git init` it, and seed it: write
`CHARTER.md` (below), a minimal `.gitignore`, and a stub `README.md` with
just the project name as an H1. Narrate each of these three files in one
sentence each.
- **Decision capture:** if adopting an *existing* non-empty folder as a Baton
project was a genuine judgment call (i.e. there was a real alternative —
e.g. the user considered starting fresh instead), capture it via the
file-based decision intake per `CLAUDE.md`'s decision-capture rule. Skip
for the routine "empty new folder" case — that's not a decision with
alternatives.

6. **Write the CHARTER + register the project.** Because goal/reasoning text
can be long, build the CHARTER string in-process and write it directly —
never pass long text as an inline shell argument (965-byte limit):

```powershell
$charterPath = Join-Path $targetFolder 'CHARTER.md'
$charterText = New-CharterContent -Name $name -Goal $goal -Audience $audience -Done $done -Reasoning $reasoning
Set-Content -Path $charterPath -Value $charterText -Encoding utf8NoBOM

$now = Get-Date -Format 'yyyy-MM-ddTHH:mm:sszzz'
Write-ProjectRecord -Record @{
id = $projectId; name = $name; folder = $targetFolder
charter_path = $charterPath; created_at = $now; last_updated = $now
last_run = $null
}

# Best-effort supplement to Grimdex/memory if present — never required.
# If a Grimdex project tier exists for this project, or auto-memory is
# active in this session, record the captured reasoning there too.
```

In `teach` mode, explain: *"I wrote your reasoning to CHARTER.md in your
project folder — that's yours to read and edit any time."*

7. **Hand off to `/baton:go` full-auto:**

```powershell
pwsh -NoProfile -File "$HOME/.claude/scripts/fleet-go.ps1" -Goal "<goal from step 4/6>" -Json
# add -Budget <n> when --budget was supplied
# add -MaxCostTier <tier> when --max-tier was supplied
```

Before running, tell the user (teach mode adds the *why*): *"Now driving
/baton:go — I'll only stop for a budget limit or an irreversible action."*

8. **Read the result and update state:**

```powershell
# $result = the parsed JSON from step 7
$rec = Read-ProjectRecord -ProjectId $projectId
$recHash = @{
id = $rec.id; name = $rec.name; folder = $rec.folder; charter_path = $rec.charter_path
created_at = $rec.created_at; last_updated = (Get-Date -Format 'yyyy-MM-ddTHH:mm:sszzz')
last_run = @{ run_id = (Split-Path -Leaf $result.run_dir); status = $result.status; at = (Get-Date -Format 'yyyy-MM-ddTHH:mm:sszzz') }
}
Write-ProjectRecord -Record $recHash
```

Narrate the run terse-one-liner style from `<run_dir>/events.jsonl`, and
surface autonomous choices from `<run_dir>/decisions.jsonl` (legibility).

9. **Report by `status`** using `Get-NextCommandRecommendation -RunStatus $result.status`:
- Print the recommended command; in `teach` mode also print its `why`.
- `completed` → also point at `<run_dir>/report.md`.
- `interrupted-budget` / `interrupted-destructive` → describe exactly what
is pending (from `$result.pending_task_id`) before recommending the resume
command; wait for the user's explicit go-ahead before re-invoking.
- `rejected` → show the `## Acceptance` section of `report.md`.
- `failed` / `plan-failed` / `plan-invalid` → show why, then the
recommendation.

10. **First-run profile write.** If `$profile` was `$null` at step 2 (this was
a genuinely new user), write a starter `user-profile.json` now with
`preferred_interview_depth = $depth` (what was actually used) and
`teaching_level = $teachLevel`, so the *next* `/baton:start` call is
already calibrated. `$depth` is only ever assigned on the new-project path
(step 4), so gate this on `$mode -eq 'new'` too — a resume that reaches
here with no prior profile (e.g. `user-profile.json` was deleted, or the
project predates this feature) must not write an unbound `$depth` into it:

```powershell
if ($mode -eq 'new' -and -not $profile) {
Write-UserProfile -Profile @{
preferred_interview_depth = $depth; teaching_level = $teachLevel
updated_at = (Get-Date -Format 'yyyy-MM-ddTHH:mm:sszzz')
}
}
```

## Arguments

$ARGUMENTS
21 changes: 21 additions & 0 deletions docs/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,26 @@ knowledge base mixed into their prompt before they answer.

---

# Front porch — the one command to begin or resume

### /baton:start
- **One-liner:** Start a new project or resume one you already began — guided in plain language, no git or coding knowledge required.
- **When you'd use it:** This is the recommended way to begin. It works whether you know exactly what you want or have no idea where to start.
- **Syntax:** `/baton:start ["<name>"] [--folder <path>] [--goal "<text>"] [--budget <n>] [--max-tier local|free|paid] [--depth light|adaptive|full] [--quiet]`
- **Arguments & flags:**
- `"<name>"` — the project's name (optional; asked for if omitted).
- `--folder <path>` — where it lives. Omit it and Baton either adopts your current folder or asks.
- `--goal "<text>"` — what you want built, if you already know. Omit it and you'll be asked.
- `--budget <n>` / `--max-tier <tier>` — passed straight through to the execution engine.
- `--depth light|adaptive|full` — override how many questions it asks. Default adapts to you over time.
- `--quiet` — turn off the plain-language explanations (teaching is on by default).
- **Under the hood:** Detects whether this is a new or existing Baton project. New: runs a guided interview, sets up the folder and git for you (explaining each step), writes a `CHARTER.md` in your project recording what you want and why, then hands off to `/baton:go` to build it full-auto. Existing: shows you where you left off and recommends the next command.
- **Where results land:** `CHARTER.md` in your project folder (yours to read/edit); `$BATON_HOME/projects/<id>/project.json` (box-private project record); run artifacts under `$BATON_HOME/runs/<run-id>/` (same as `/baton:go`).
- **Plain example:** `/baton:start "Acme API"` → asks a few questions, sets everything up, and starts building.
- **Gotchas:** Aliases `/baton:init` and `/baton:initialize` do exactly the same thing — pick whichever name you remember. It only stops mid-run for a budget limit or an action that's hard to undo; everything else runs on your behalf.

---

# Jobs — track a piece of work start to finish

A **job** is a tracked unit of work (a feature, a bug, an investigation). It has
Expand Down Expand Up @@ -361,6 +381,7 @@ observations from the noisy journal into the clean catalog.

| Command | One-liner |
|---|---|
| `/baton:start ["<name>"]` | Start or resume a project — the front porch |
| `/baton:job-start "<brief>"` | Start a tracked job |
| `/baton:job-status` | Where am I on the current job |
| `/baton:job-list [--all\|--active\|--done]` | List jobs |
Expand Down
34 changes: 22 additions & 12 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,34 @@ After running `pwsh -NoProfile -File scripts\bootstrap.ps1 -Force`, you have:

## A typical session — start to finish

### 1. Open a project
### 1. Start (or resume) a project

```powershell
cd path\to\some\repo
claude # or your IDE's Claude integration
```

The hook auto-tags every model dispatch with the project name; the dashboard portfolio panel shows it.

### 2. Open a job

```
/baton:job-start "rewrite the auth middleware"
/baton:start "rewrite the auth middleware"
```

Creates `$BATON_HOME/jobs/<id>/` (default `~/.baton/jobs/<id>/`) with `manifest.yaml`, `brief.md`, `phase-log.md`, `lessons.md`. Phase starts at `research`.
`/baton:start` is the recommended on-ramp — it works whether this is a brand
new project or one you've already begun, and it doesn't assume you know git or
how to structure a repo. It asks what you're building (skipping questions
you've already answered via flags), sets up the folder and git for you if
needed, writes a plain-language `CHARTER.md` recording what you want and why,
then drives the work full-auto via `/baton:go` — stopping only for a budget
limit or a hard-to-undo action.

The hook auto-tags every model dispatch with the project name; the dashboard portfolio panel shows it.

If you'd rather track the work as a manual job without the guided interview or
full-auto execution, `/baton:job-start "<brief>"` remains available — it
creates `$BATON_HOME/jobs/<id>/` (default `~/.baton/jobs/<id>/`) with
`manifest.yaml`, `brief.md`, `phase-log.md`, `lessons.md`, starting at the
`research` phase, and you drive each phase yourself.

### 3. Research the problem
### 2. Research the problem

```
/baton:research "what's the safest way to migrate session tokens without invalidating logins?"
Expand All @@ -51,21 +61,21 @@ For decision-making rather than research:
/baton:council "should we adopt sliding-window refresh tokens?" --providers claude-cli,codex
```

### 4. Capture a lesson
### 3. Capture a lesson

```
/baton:job-lesson knowledge "session tokens are HS256 today; rotating without invalidating requires a grace window in the validator"
```

### 5. Design (still in conversation — no slash command needed)
### 4. Design (still in conversation — no slash command needed)

Write a design spec to `<job>/phases/design/<topic>.md` (or anywhere). When you have a spec, advance the phase:

```
/baton:job-phase next # research → design (or design → code.sprint-1)
```

### 6. Code phase (Plan 6)
### 5. Code phase (Plan 6)

```
/baton:code-decompose docs/specs/auth-rewrite.md
Expand All @@ -85,7 +95,7 @@ Dispatches one Agent subagent per task in an isolated git worktree (Claude Code'

Surfaces likely conflicts via `files_touched` overlap, then prints the cherry-pick plan. Add `--apply` to execute.

### 7. Wrap up
### 6. Wrap up

```
/baton:job-phase done
Expand Down
Loading