Skip to content

[Air #1840] feat: afx decisions init turns on the Decisions tab - #1841

Merged
waleedkadous merged 7 commits into
mainfrom
builder/air-1840
Oct 19, 2026
Merged

waleedkadous merged 7 commits into
mainfrom
builder/air-1840

Conversation

@waleedkadous

@waleedkadous waleedkadous commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

afx decisions init is the one command an owner runs to start using decisions. It writes the decisions file from its template, prints where the file went, says that the Decisions tab appears within a few seconds, and gives the one sentence to tell the architect: "Route every ask for my word through the decisions file."

Closes #1840

What Changed

  • Template as code. servers/decisions/template.ts exports DECISIONS_FILE_TEMPLATE, which is the file Fix #1836: Decisions tab reads time-only and missing stamps without a warning #1837 ships. decision-protocol-doc.test.ts asserts that section 4's fenced template equals it, and that section 4 names the command above the template, so the doc and the code cannot drift.
  • Command. commands/decisions.ts plus its wiring in cli.ts. The target is --path, else dashboard.decisionsFile, else codev/state/pending-decisions.md. Resolution and containment reuse the tab's own configuredDecisionsPath and resolveDecisionsPath, so a path the tab would refuse (.., or a symlink out of the workspace) is refused here with the same rule. The command creates codev/state/ if it is missing. The write uses flag: 'wx', so an existing file is refused, and so is a directory or a dangling symlink at that path. Nothing is ever overwritten, and there is no --force.
  • Docs, in both trees. A new ### afx decisions init entry in the command reference. The Decisions tab section of agent-farm.md now opens with the command as the way to turn the tab on. Section 4 of decision-protocol.md names the command above its template. The architect role says to run afx decisions init and follow the doc when the owner asks to use decisions. That section stays three lines, as the issue asked.

Key Decisions

  • --path must be relative, the same rule as dashboard.decisionsFile, so the printed path can be pasted into config as is. An empty --path is refused too.
  • A --path the tab does not read gets an honest message. The tab reads only the configured path. So when --path differs from it, the command does not claim the tab will appear. It prints the setting that would show the file instead, as nested JSON: {"dashboard":{"decisionsFile":"<path>"}}. The command does not write config, because the issue does not ask for that.
  • A dashboard.decisionsFile the tab refuses fails the command loudly, even with --path. That covers an absolute path, a value that is not a string, and a path resolving outside the workspace. The command reports the tab's own error rather than falling back to the default.
  • Template line order stays _Status: then _Zone:, which is what Fix #1836: Decisions tab reads time-only and missing stamps without a warning #1837 shipped and what the existing doc test pins.

Test Plan

  • Unit tests (decisions-init.test.ts, 8 tests). They cover: creating codev/state/ and the file from the template, after which decisionsFilePresent is true and the file parses with no problems; refusing an existing file and leaving it byte-identical; honouring dashboard.decisionsFile; --path winning over config; refusing a path outside the workspace, whether through .., a symlinked codev/state, or a config .., with nothing written; refusing an absolute or empty --path, an absolute config value, and an out-of-workspace config even when --path is given; and the printed output for both the default case and a --path the tab does not read.
  • Doc test: section 4's template equals DECISIONS_FILE_TEMPLATE. The Decisions tab section in both trees opens with the command, and the architect role in both trees names it.
  • Live check (new e2e in decisions-tab.test.ts). With a dashboard already open on a workspace that has no decisions file, the test runs the built bin/afx.js decisions init in that workspace. The Decisions tab appears in about 2 s, and a page-scope marker set before the command shows the page was not reloaded. The tab shows codev/state/pending-decisions.md, 0 open, and "No open decisions." I looked at the screenshot. The whole Decisions suite passes (12/12) on an isolated test Tower (port 14101, throwaway state and socket dirs).
  • Ran the built CLI by hand in a scratch workspace: create, refuse an existing file, refuse --path ../out.md, --path notes/owner.md with the config hint, and afx decisions --help.
  • Build passes; the full packages/codev suite passes (6526 passed, 48 skipped).

CMAP

gemini=APPROVE, codex=REQUEST_CHANGES, claude=COMMENT. All points that held up are fixed in the second commit:

  • codex: the --path hint printed what reads as a flat config key. It now prints nested JSON.
  • claude: a config resolving outside the workspace was not refused when --path was given. It now is, the same as an absolute config.
  • claude: added afx decisions init to the command reference in both trees. The refusal message for an existing path no longer claims a directory "holds the owner's rulings".
  • Claude's optional point, listing the command in the afx skill's "Other commands" block, was added at the architect's request in the third commit. It's in all four copies: .claude and .codex, in both trees.

Review Notes

The --path message is the one behaviour not spelled out in the issue (see Key Decisions). Without it, the command would claim the tab appears when it would not.

🤖 Generated with Claude Code

waleedkadous and others added 5 commits October 19, 2026 10:21
Creates the decisions file from its template at --path, else
dashboard.decisionsFile, else codev/state/pending-decisions.md, held to
the tab's own containment rule, and refuses a file that already exists.
The template is a code constant; the protocol doc's section 4 is pinned
to it. Architect role and the Decisions tab docs name the command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the --path config hint as nested JSON, refuse a dashboard.decisionsFile
the tab refuses even when --path is given, word the EEXIST refusal for any
existing path, and list the command in the agent-farm command reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@waleedkadous

Copy link
Copy Markdown
Contributor Author

Thank you — this is the command the tab was missing, and it is built the right way: the path rule is delegated to the tab's own resolver so the two can never disagree, and the wx write refuses overwrite, directory and dangling-symlink in one primitive. I ran the built CLI myself in a scratch workspace: first run creates the UTC template and prints the three lines; second run refuses; an absolute path and ../outside.md are both refused with clear messages. Twins are byte-identical for the role and the protocol doc, and your agent-farm.md additions match in both trees (the pre-existing drift there is #1827). Consult verdict APPROVE.

One line before merge: add afx decisions init to the afx skill (.claude/skills/afx/SKILL.md, and its skeleton twin if one is shipped). The architect role now tells agents to run it, and the project rules tell them to check the skill before running any afx command, so without the entry the loop stays open.

Not for this PR: the ### afx decisions init heading in the command reference names a subcommand where its siblings name top-level commands; fine until decisions grows a second subcommand.

@waleedkadous
waleedkadous merged commit 3f90f89 into main Oct 19, 2026
7 checks passed
waleedkadous added a commit that referenced this pull request Oct 19, 2026
waleedkadous added a commit that referenced this pull request Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

afx decisions init: one command to turn on the Decisions tab

1 participant