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
1 change: 1 addition & 0 deletions .claude/skills/afx/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,5 +257,6 @@ afx open <file> # Open file in annotation viewer (NOT system ope
afx shell # Spawn utility shell
afx attach # Attach to running builder terminal
afx rename <name> # Rename current shell session
afx decisions init # Create the decisions file; turns on the Decisions tab
afx architect # Start architect session in current terminal
```
1 change: 1 addition & 0 deletions .codex/skills/afx/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,5 +257,6 @@ afx open <file> # Open file in annotation viewer (NOT system ope
afx shell # Spawn utility shell
afx attach # Attach to running builder terminal
afx rename <name> # Rename current shell session
afx decisions init # Create the decisions file; turns on the Decisions tab
afx architect # Start architect session in current terminal
```
1 change: 1 addition & 0 deletions codev-skeleton/.claude/skills/afx/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,5 +235,6 @@ afx open <file> # Open file in annotation viewer (NOT system ope
afx shell # Spawn utility shell
afx attach # Attach to running builder terminal
afx rename <name> # Rename current shell session
afx decisions init # Create the decisions file; turns on the Decisions tab
afx architect # Start architect session in current terminal
```
1 change: 1 addition & 0 deletions codev-skeleton/.codex/skills/afx/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,5 +235,6 @@ afx open <file> # Open file in annotation viewer (NOT system ope
afx shell # Spawn utility shell
afx attach # Attach to running builder terminal
afx rename <name> # Rename current shell session
afx decisions init # Create the decisions file; turns on the Decisions tab
afx architect # Start architect session in current terminal
```
17 changes: 17 additions & 0 deletions codev-skeleton/resources/commands/agent-farm.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,21 @@ Dismissal is CLI-only; the dashboard and VSCode held-count indicators surface th

---

### afx decisions init

Turn on the dashboard's Decisions tab (Issue #1840).

```bash
afx decisions init [--path <file>]
```

**Options:**
- `--path <file>` - File to create, relative to the workspace root (default: `dashboard.decisionsFile`, else `codev/state/pending-decisions.md`)

Creates the decisions file from its template and prints the sentence to tell the main architect. It never replaces an existing file, and refuses a path outside the workspace. See [Decisions tab](#decisions-tab).

---

### afx interrupt

Interrupt a builder mid-turn by sending an ESC keystroke to its PTY.
Expand Down Expand Up @@ -934,6 +949,8 @@ Both are Tower-global (they apply to the whole Tower, not per-project) and optio

### Decisions tab

Turn the tab on with `afx decisions init`. It creates the decisions file from its template, prints where it went, and gives the one sentence to tell the main architect: "Route every ask for my word through the decisions file." It refuses a file that already exists, because that file holds the owner's rulings, and a path outside the workspace. `--path <file>` creates another file, relative to the workspace root; the tab shows it once `dashboard.decisionsFile` names it.

When a workspace has a pending-decisions file, the dashboard shows a **Decisions** tab (Spec 1819). The tab is a view of that file. Each item under `## Open` becomes a card with a click box per option (the first option, the recommended one, is marked) and a comment box. Submitting writes the chosen word, then the comment, on the lines right after the item's `**Your word:**` line, exactly as the owner would type them, and changes nothing else. `## Ruled` is shown below as a collapsed, read-only list. The file is the only state. While the tab is open it re-reads the file every 2 seconds, so edits made elsewhere appear without a reload, and an unsent draft survives them.

The file's format and the process around it are in [`decision-protocol.md`](../decision-protocol.md): one hub architect, `main`, is the only agent that edits the file, other architects send it their items, and the hub relays each ruling. The tab reads exactly the item format that document describes.
Expand Down
5 changes: 3 additions & 2 deletions codev-skeleton/resources/decision-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,9 @@ A second question gets a second pair of lines under the first.

## 4. The file

Create it at `codev/state/pending-decisions.md`, or at the path `dashboard.decisionsFile` names;
the Decisions tab appears once the file exists.
Create it with `afx decisions init`, which writes the template below to
`codev/state/pending-decisions.md`, or to the path `dashboard.decisionsFile` names, and never
replaces a file that is already there. The Decisions tab appears once the file exists.

```markdown
# Pending owner decisions — all architects (hub: main)
Expand Down
4 changes: 2 additions & 2 deletions codev-skeleton/roles/architect.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ human should be able to answer from your message without opening the diff.
### The owner decisions file

A workspace may collect every ask for the human's word in `codev/state/pending-decisions.md`,
the dashboard's **Decisions** tab, with one architect named `main` as the hub and its only
editor. The process and the item format are in `codev/resources/decision-protocol.md`.
the dashboard's **Decisions** tab, with the architect `main` as hub and only editor. When the
owner asks to use decisions, run `afx decisions init` and follow `codev/resources/decision-protocol.md`.

## UX verification

Expand Down
17 changes: 17 additions & 0 deletions codev/projects/1840-afx-decisions-init-one-command/status.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
id: '1840'
title: afx-decisions-init-one-command
protocol: air
phase: pr
plan_phases: []
current_plan_phase: null
gates:
pr:
status: approved
requested_at: '2026-10-19T17:35:05.884Z'
approved_at: '2026-10-19T18:32:28.632Z'
iteration: 1
build_complete: false
history: []
started_at: '2026-10-19T17:21:36.050Z'
updated_at: '2026-10-19T18:32:28.633Z'
pr_ready_for_human: false
17 changes: 17 additions & 0 deletions codev/resources/commands/agent-farm.md
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,21 @@ Dismissal is CLI-only; the dashboard and VSCode held-count indicators surface th

---

### afx decisions init

Turn on the dashboard's Decisions tab (Issue #1840).

```bash
afx decisions init [--path <file>]
```

**Options:**
- `--path <file>` - File to create, relative to the workspace root (default: `dashboard.decisionsFile`, else `codev/state/pending-decisions.md`)

Creates the decisions file from its template and prints the sentence to tell the main architect. It never replaces an existing file, and refuses a path outside the workspace. See [Decisions tab](#decisions-tab).

---

### afx interrupt

Interrupt a builder mid-turn by sending an ESC keystroke to its PTY.
Expand Down Expand Up @@ -1164,6 +1179,8 @@ Both are Tower-global (they apply to the whole Tower, not per-project) and optio

### Decisions tab

Turn the tab on with `afx decisions init`. It creates the decisions file from its template, prints where it went, and gives the one sentence to tell the main architect: "Route every ask for my word through the decisions file." It refuses a file that already exists, because that file holds the owner's rulings, and a path outside the workspace. `--path <file>` creates another file, relative to the workspace root; the tab shows it once `dashboard.decisionsFile` names it.

When a workspace has a pending-decisions file, the dashboard shows a **Decisions** tab (Spec 1819). The tab is a view of that file. Each item under `## Open` becomes a card with a click box per option (the first option, the recommended one, is marked) and a comment box. Submitting writes the chosen word, then the comment, on the lines right after the item's `**Your word:**` line, exactly as the owner would type them, and changes nothing else. `## Ruled` is shown below as a collapsed, read-only list. The file is the only state. While the tab is open it re-reads the file every 2 seconds, so edits made elsewhere appear without a reload, and an unsent draft survives them.

The file's format and the process around it are in [`decision-protocol.md`](../decision-protocol.md): one hub architect, `main`, is the only agent that edits the file, other architects send it their items, and the hub relays each ruling. The tab reads exactly the item format that document describes.
Expand Down
5 changes: 3 additions & 2 deletions codev/resources/decision-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,9 @@ A second question gets a second pair of lines under the first.

## 4. The file

Create it at `codev/state/pending-decisions.md`, or at the path `dashboard.decisionsFile` names;
the Decisions tab appears once the file exists.
Create it with `afx decisions init`, which writes the template below to
`codev/state/pending-decisions.md`, or to the path `dashboard.decisionsFile` names, and never
replaces a file that is already there. The Decisions tab appears once the file exists.

```markdown
# Pending owner decisions — all architects (hub: main)
Expand Down
4 changes: 2 additions & 2 deletions codev/roles/architect.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ human should be able to answer from your message without opening the diff.
### The owner decisions file

A workspace may collect every ask for the human's word in `codev/state/pending-decisions.md`,
the dashboard's **Decisions** tab, with one architect named `main` as the hub and its only
editor. The process and the item format are in `codev/resources/decision-protocol.md`.
the dashboard's **Decisions** tab, with the architect `main` as hub and only editor. When the
owner asks to use decisions, run `afx decisions init` and follow `codev/resources/decision-protocol.md`.

## UX verification

Expand Down
41 changes: 41 additions & 0 deletions codev/state/air-1840_thread.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# air-1840 — `afx decisions init`

## 2026-10-19 — implement

- Template lives in `servers/decisions/template.ts` (`DECISIONS_FILE_TEMPLATE`); the doc test pins
section 4's fenced block to it (`fileSkeleton + '\n' === constant`). Kept the doc's line order
(`_Status:` then `_Zone:`), which is what #1837 shipped and what the existing test pins — the
issue lists `_Zone` before `_Status`, read as a list of contents, not an order.
- Command: `commands/decisions.ts`. Resolution and containment reuse `configuredDecisionsPath` +
`resolveDecisionsPath` from `servers/decisions/file.ts`, so the command and the tab apply one
rule. The write is `flag: 'wx'`, so an existing file, directory or dangling symlink at the path
is refused without a check-then-write race.
- `--path` must be relative (same rule as `dashboard.decisionsFile`), so the printed path can go
into config verbatim.
- Judgment call: when `--path` names a file the tab does not read (it differs from the configured
path), the command does not claim the tab will appear; it prints the `dashboard.decisionsFile`
setting that shows it instead. Writing config is not in the issue, so it does not.
- Architect role: kept the section at three lines, as asked, by folding the doc pointer into the
new sentence.

## 2026-10-19 — PR #1841, CMAP round 1

gemini=APPROVE, codex=REQUEST_CHANGES, claude=COMMENT (first run failed: `consult --type pr` from a
builder needs `--issue 1840`; it could not infer the project).

Fixed:
- codex: the `--path` hint printed `"dashboard.decisionsFile": "…"`, which reads as a flat key; it
now prints the nested JSON `{"dashboard":{"decisionsFile":"…"}}`.
- claude: an absolute config aborted `init --path`, but a config resolving outside the workspace
did not. Now any config the tab refuses is refused here too, `--path` or not (fail loud).
- claude: added `### afx decisions init` to the command reference in both trees; the EEXIST message
no longer claims a directory "holds the owner's rulings".

Not taken: listing the command in the afx skill's "Other commands" block (optional; that list is
already incomplete). `_Status:`/`_Zone:` order kept, which claude agreed with.

## 2026-10-19 — architect review

Architect (main) approved the integration review and asked for one line in the afx skill's
"Other commands" block: added to all four copies (`.claude`/`.codex`, both trees; each pair kept
byte-identical). pr gate stays pending; the architect takes the merge word to the owner.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { parseDecisions } from '../servers/decisions/parse.js';
import { spliceRuling } from '../servers/decisions/splice.js';
import { rulingNotice } from '../servers/decisions/notice.js';
import { resolveStamp } from '../servers/decisions/stamp.js';
import { DECISIONS_FILE_TEMPLATE } from '../servers/decisions/template.js';

const REPO = resolve(import.meta.dirname, '../../../../..');
const read = (rel: string) => readFileSync(resolve(REPO, rel), 'utf8');
Expand Down Expand Up @@ -49,6 +50,13 @@ describe('decision-protocol.md — its examples are what the tab parses', () =>
expect(parsed.items).toEqual([]);
});

it('the file skeleton is the template `afx decisions init` writes, and section 4 names the command above it (#1840)', () => {
expect(`${fileSkeleton}\n`).toBe(DECISIONS_FILE_TEMPLATE);
const section4 = doc.slice(doc.indexOf('## 4. The file\n'));
expect(section4.indexOf('`afx decisions init`')).toBeGreaterThan(0);
expect(section4.indexOf('`afx decisions init`')).toBeLessThan(section4.indexOf('```markdown'));
});

it('the item template reads its id, question and options; the first option is recommended', () => {
const [item] = parseDecisions(posted(template)).items;
expect(item.id).toBe('<name>-<n>');
Expand Down Expand Up @@ -225,11 +233,13 @@ describe('decision-protocol.md — reaches both trees and is linked where adopte
const rel = `${tree}/resources/commands/agent-farm.md`;
const section = read(rel).match(/^### Decisions tab\n[\s\S]*?(?=^### )/m)?.[0] ?? '';
expect(section).toContain('](../decision-protocol.md)');
expect(section.split('\n\n')[1]).toMatch(/^Turn the tab on with `afx decisions init`\./);
expect(existsSync(resolve(REPO, dirname(rel), '../decision-protocol.md'))).toBe(true);
});

it(`${tree}: the architect role points at the doc`, () => {
expect(read(`${tree}/roles/architect.md`)).toContain('`codev/resources/decision-protocol.md`');
expect(read(`${tree}/roles/architect.md`)).toContain('run `afx decisions init` and follow `codev/resources/decision-protocol.md`');
});
}

Expand Down
Loading
Loading