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
11 changes: 7 additions & 4 deletions .abcd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ tree written for the reader of the CLI.

- **[`development/`](development/)** — the durable record (committed): plans,
research, and architecture decisions. The specification the build works from.
- **[`work/`](work/)** — working memory, committed shared orientation:
`CONTEXT.md` (load-first standing facts) and `DECISIONS.md` (one-line decision
log).

Working memory (`.work/`, committed shared orientation, and `.work.local/`,
git-ignored local ephemera) currently sits at the repo root; a phase-2 migration
folds it under this namespace (`.abcd/work/`, `.abcd/.work.local/`). Until then,
see [`../AGENTS.md`](../AGENTS.md) for the working-memory split.
Local, ephemeral working memory — the `NEXT.md` handover, scratch output, and
logs — lives in the git-ignored `.work.local/` alongside these, hidden via
`.git/info/exclude` and never committed. See [`../AGENTS.md`](../AGENTS.md) for
the working-memory split.
49 changes: 49 additions & 0 deletions .abcd/development/plans/2026-07-08-v0.7.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# ferry v0.7.2 — working memory folds into the `.abcd/` namespace

**Status:** shipped in v0.7.2 — the working-memory fold and its scaffold ripple
are delivered.
**Owner:** REPPL. **Type:** implementation plan (Diátaxis: one plan, no mixing).

## 1. Goal and scope

Complete the `.abcd/` alignment begun in v0.7.1 (which moved the durable record —
plans, research, decisions — into `.abcd/development/`). v0.7.1 deliberately
deferred the working-memory tier; v0.7.2 folds it in, so the whole
developer-facing surface lives under one namespace and `ferry agents scaffold`
stamps that same layout into every repo it onboards.

In scope:

- Fold ferry's own committed working memory: `git mv .work/CONTEXT.md` and
`.work/DECISIONS.md` into `.abcd/work/`, with a lean `.abcd/work/README.md`
and an updated `.abcd/README.md`.
- Change the scaffold generator (`internal/agents/scaffold.go`) so a scaffolded
repo gets a committed `.abcd/work/` (`DECISIONS.md`, `CONTEXT.md`) and a
git-ignored `.abcd/.work.local/` (`NEXT.md`, `scratch/`, `logs/`, plus
`DECISIONS.md`/`CONTEXT.md`/`ISSUES.md` in `--private` mode). The
`info/exclude` entry becomes `.abcd/.work.local/`.
- Regenerate the golden fixtures (`scaffold_golden_test.go`, `scaffold_test.go`)
in lockstep — they fail loudly until they match the new layout.
- Repoint the convention docs and the `agents scaffold` help/CLI reference at the
new paths.

## 2. Out of scope (deferred)

- The physical move of ferry's own local `.work.local/` contents to
`.abcd/.work.local/`, and the matching `scripts/release.sh` / CI update — these
touch the live session and harness hooks, so they land separately.
- The sibling terminal/emacs/tmux domains (v0.7.3).
- Any cross-repo convention change to the shared `ABCDevelopment/CLAUDE.md`.

## 3. Approach

The move mirrors the v0.7.1 docs migration: `git mv` plus text edits, no runtime
behaviour change. The scaffold generator centralises every working-memory dest in
one declarative table (`scaffoldLayout`) plus the `ensureWorkLocalDirs` and
`excludeWorkLocal` helpers, so retargeting is a handful of edits; the golden
characterisation tests then pin the exact created-path set, the exact stdout, and
the exact `info/exclude` line, so any drift from the new layout is a loud test
failure — that lockstep is the safety net.

The change is fully reversible: `git mv` plus text edits, no data migration and no
release cutover.
File renamed without changes.
File renamed without changes.
19 changes: 19 additions & 0 deletions .abcd/work/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Working memory (committed)

The shared, committed tier of ferry's working memory — the standing facts the
next session needs before it can act, kept in the repo so every clone and every
agent starts from the same orientation. Mirrors the sibling `abcd-cli`'s
`.abcd/work/`.

| File | What it holds |
|---|---|
| [`CONTEXT.md`](CONTEXT.md) | Curated, load-first summary of ferry's standing facts and invariants. Read it first. |
| [`DECISIONS.md`](DECISIONS.md) | One-line-per-entry log of session decisions — rejected alternatives and chosen tradeoffs a future session would otherwise re-litigate. |

Because this tier is committed, its contents follow the repository's privacy
rules: no local absolute paths, secrets, or live data. Local, ephemeral working
memory — the `NEXT.md` handover, scratch output, and logs — lives in the
git-ignored [`../.work.local/`](../.work.local/) instead, hidden via
`.git/info/exclude` and never committed. See
[ADR 0002](../development/decisions/0002-work-memory-public-private-split.md)
for the public/private split.
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ on the internal packages, and the full eval suite against a real Linux binary.

## Working memory

Load `.work/CONTEXT.md` first — it is the curated, load-first summary of ferry's
standing facts and invariants. Record session handoff in `.work.local/NEXT.md`
(git-ignored, local-only), not in `.work/`. See
Load `.abcd/work/CONTEXT.md` first — it is the curated, load-first summary of
ferry's standing facts and invariants. Record session handoff in
`.abcd/.work.local/NEXT.md` (git-ignored, local-only), not in `.abcd/work/`. See
[ADR 0002](.abcd/development/decisions/0002-work-memory-public-private-split.md) for the split.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ called out in a **Breaking** section. See

## [Unreleased]

## [0.7.2] - 2026-07-08

### Changed

- **Working memory moves into the `.abcd/` namespace.** ferry's committed
working memory moves from `.work/` to `.abcd/work/` (holding `CONTEXT.md`, the
load-first standing facts, and `DECISIONS.md`, the one-line decision log), and
`ferry agents scaffold` now creates the `.abcd/{work,.work.local}` layout: a
scaffolded repo gets a committed `.abcd/work/` and a git-ignored
`.abcd/.work.local/` (`NEXT.md`, `scratch/`, `logs/`, hidden via
`.git/info/exclude`) instead of the root-level `.work/` and `.work.local/`.
This completes the `.abcd/` alignment begun in 0.7.1.

## [0.7.1] - 2026-07-08

### Changed
Expand Down
16 changes: 8 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ sequential number
reservation registry.
- If two branches mint the same `NNNN`, a duplicate-`NNNN` lint fails CI and the
second branch to merge renumbers its ADR. Do not resolve the clash by force.
- One-line session decisions live in `.work/DECISIONS.md`; promote a decision to
a `.abcd/development/decisions/` ADR when it shapes architecture or is
expensive to reverse.
- One-line session decisions live in `.abcd/work/DECISIONS.md`; promote a
decision to a `.abcd/development/decisions/` ADR when it shapes architecture or
is expensive to reverse.

## Working memory

Curated standing facts load first from `.work/CONTEXT.md` (committed). Session
handoff, scratch output, and logs live under `.work.local/` (git-ignored via
`.git/info/exclude`, never committed). See
Curated standing facts load first from `.abcd/work/CONTEXT.md` (committed).
Session handoff, scratch output, and logs live under `.abcd/.work.local/`
(git-ignored via `.git/info/exclude`, never committed). See
[ADR 0002](.abcd/development/decisions/0002-work-memory-public-private-split.md)
for the rationale. Because `.work/` is committed, its contents follow the repository's
privacy rules: no local absolute paths, secrets, or live data.
for the rationale. Because `.abcd/work/` is committed, its contents follow the
repository's privacy rules: no local absolute paths, secrets, or live data.
12 changes: 6 additions & 6 deletions cmd/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ var agentsScaffoldCmd = &cobra.Command{
Short: "Set a project repo up for the multi-tool agent pipeline",
Long: `Set a project repo up for the multi-tool agent pipeline.

Both modes create the local-only runtime layout: .work.local/{scratch,logs},
Both modes create the local-only runtime layout: .abcd/.work.local/{scratch,logs},
hidden via the git info/exclude mechanism (never committed; .gitignore is
never touched).

Default mode (your own repo — tracked files): an AGENTS.md router stamped from
the config repo's template ({{PROJECT}}/{{DATE}} substituted), CLAUDE.md and
GEMINI.md as relative symlinks to AGENTS.md inside the repo, a committed
.work/ (NEXT.md, DECISIONS.md), the docs/ hierarchy with its map
.abcd/work/ (DECISIONS.md, CONTEXT.md), the docs/ hierarchy with its map
(docs/README.md), and a pre-commit config when the repo has none.

--attribution (tracked mode only) marks a repo that REQUIRES AI disclosure,
Expand All @@ -52,9 +52,9 @@ prepare-commit-msg hook (a kernel-style Assisted-by trailer on agent-authored
commits — never Co-Authored-By), sets core.hooksPath to .githooks (per clone),
and appends the AI-attribution section to AGENTS.md.

--private mode (a repo you don't own — zero tracked trace): .work.local/ only
(NEXT.md, DECISIONS.md, ISSUES.md). No AGENTS.md, no symlinks, no docs, no
tracked file touched. Not combinable with --attribution.
--private mode (a repo you don't own — zero tracked trace): .abcd/.work.local/
only (NEXT.md, DECISIONS.md, CONTEXT.md, ISSUES.md). No AGENTS.md, no symlinks,
no docs, no tracked file touched. Not combinable with --attribution.

Idempotent; never overwrites an existing file.`,
Args: cobra.RangeArgs(1, 2),
Expand All @@ -79,7 +79,7 @@ Requires the agents domain to be enabled ("agents = true" under [manage]).`,
}

func init() {
agentsScaffoldCmd.Flags().Bool("private", false, "leave no tracked trace: .work.local/ only, excluded via git info/exclude")
agentsScaffoldCmd.Flags().Bool("private", false, "leave no tracked trace: .abcd/.work.local/ only, excluded via git info/exclude")
agentsScaffoldCmd.Flags().Bool("attribution", false, "this repo requires AI disclosure: install the Assisted-by commit hook and AGENTS.md policy section")
agentsScaffoldCmd.MarkFlagsMutuallyExclusive("private", "attribution")
agentsCmd.AddCommand(agentsScaffoldCmd, agentsAdoptCmd)
Expand Down
24 changes: 12 additions & 12 deletions docs/how-to/scaffold-a-repo.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
## Goal

Set a **project** repo up for the multi-tool agent pipeline — the AGENTS.md router, the
`CLAUDE.md`/`GEMINI.md` bridges, the committed `.work/` memory, the `docs/` map, and the
local-only runtime layout — in one idempotent command. For the model behind the agents
`CLAUDE.md`/`GEMINI.md` bridges, the committed `.abcd/work/` memory, the `docs/` map, and
the local-only runtime layout — in one idempotent command. For the model behind the agents
domain, see [The agents domain](../explanation/agents.md).

## Command
Expand All @@ -19,11 +19,11 @@ directory's base name. Idempotent; never overwrites an existing file.
## What it creates

The layout separates **committed project memory** from **local-only runtime
artefacts**: everything under `.work/` is meant to be committed, while
scratch output and logs always live in `.work.local/` and never reach git.
Both modes create `.work.local/scratch/` and `.work.local/logs/` and hide the
whole `.work.local/` directory via the checkout-local git `info/exclude` —
`.gitignore` is never touched.
artefacts**: everything under `.abcd/work/` is meant to be committed, while
scratch output and logs always live in `.abcd/.work.local/` and never reach git.
Both modes create `.abcd/.work.local/scratch/` and `.abcd/.work.local/logs/` and
hide the whole `.abcd/.work.local/` directory via the checkout-local git
`info/exclude` — `.gitignore` is never touched.

Default (tracked) mode, for a repo you own:

Expand All @@ -33,8 +33,8 @@ Default (tracked) mode, for a repo you own:
| `CLAUDE.md`, `GEMINI.md` | Relative symlinks to `AGENTS.md` **inside the project repo** (project-tracked content — ferry does not deploy these to `$HOME`) |
| `docs/README.md` | The user-facing documentation map, stamped from `agents/templates/docs-README.md`: the four Diátaxis directories and the root-markdown allowlist |
| `.abcd/development/plans/`, `.abcd/development/research/`, `.abcd/development/decisions/` | Developer-record directories, created up front — dated plans and research (`YYYY-MM-DD-topic.md`) and ADRs (MADR, `NNNN-title.md`); `docs/` stays user-facing Diátaxis, whose content directories are created on first use |
| `.work/DECISIONS.md`, `.work/CONTEXT.md` | Committed decision log and curated standing facts (the load-first summary) |
| `.work.local/NEXT.md`, `.work.local/scratch/`, `.work.local/logs/` | Local-only session handoff and runtime artefacts, hidden via git `info/exclude` |
| `.abcd/work/DECISIONS.md`, `.abcd/work/CONTEXT.md` | Committed decision log and curated standing facts (the load-first summary) |
| `.abcd/.work.local/NEXT.md`, `.abcd/.work.local/scratch/`, `.abcd/.work.local/logs/` | Local-only session handoff and runtime artefacts, hidden via git `info/exclude` |
| `.pre-commit-config.yaml` | Copied from the template, only when the repo has none |

`--attribution` (tracked mode only) marks a repo that **requires AI
Expand All @@ -54,8 +54,8 @@ refused: a repo you do not own is not yours to set attribution policy in.

| Item | Role |
|---|---|
| `.work.local/NEXT.md`, `DECISIONS.md`, `ISSUES.md` | The same logs plus a private observation list, alongside the `scratch/` and `logs/` dirs |
| git `info/exclude` entry | Hides `.work.local/` locally; never committed or pushed |
| `.abcd/.work.local/NEXT.md`, `DECISIONS.md`, `CONTEXT.md`, `ISSUES.md` | The same logs plus a private observation list, alongside the `scratch/` and `logs/` dirs |
| git `info/exclude` entry | Hides `.abcd/.work.local/` locally; never committed or pushed |

Anything already sitting where a bridge symlink would go is left untouched: a
real file is skipped with a message (merge it into `AGENTS.md` first), and a
Expand All @@ -70,7 +70,7 @@ directory's `info/exclude`, which is where git reads it.
## Result

The repo carries the full agent-pipeline scaffold, committable in one go (bar the
git-ignored `.work.local/`). Re-running the command is safe: it only fills in what is
git-ignored `.abcd/.work.local/`). Re-running the command is safe: it only fills in what is
missing and never overwrites an existing file.

## Related documentation
Expand Down
12 changes: 6 additions & 6 deletions docs/reference/cli/ferry_agents_scaffold.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ Set a project repo up for the multi-tool agent pipeline

Set a project repo up for the multi-tool agent pipeline.

Both modes create the local-only runtime layout: .work.local/{scratch,logs},
Both modes create the local-only runtime layout: .abcd/.work.local/{scratch,logs},
hidden via the git info/exclude mechanism (never committed; .gitignore is
never touched).

Default mode (your own repo — tracked files): an AGENTS.md router stamped from
the config repo's template ({{PROJECT}}/{{DATE}} substituted), CLAUDE.md and
GEMINI.md as relative symlinks to AGENTS.md inside the repo, a committed
.work/ (NEXT.md, DECISIONS.md), the docs/ hierarchy with its map
.abcd/work/ (DECISIONS.md, CONTEXT.md), the docs/ hierarchy with its map
(docs/README.md), and a pre-commit config when the repo has none.

--attribution (tracked mode only) marks a repo that REQUIRES AI disclosure,
Expand All @@ -22,9 +22,9 @@ prepare-commit-msg hook (a kernel-style Assisted-by trailer on agent-authored
commits — never Co-Authored-By), sets core.hooksPath to .githooks (per clone),
and appends the AI-attribution section to AGENTS.md.

--private mode (a repo you don't own — zero tracked trace): .work.local/ only
(NEXT.md, DECISIONS.md, ISSUES.md). No AGENTS.md, no symlinks, no docs, no
tracked file touched. Not combinable with --attribution.
--private mode (a repo you don't own — zero tracked trace): .abcd/.work.local/
only (NEXT.md, DECISIONS.md, CONTEXT.md, ISSUES.md). No AGENTS.md, no symlinks,
no docs, no tracked file touched. Not combinable with --attribution.

Idempotent; never overwrites an existing file.

Expand All @@ -37,7 +37,7 @@ ferry agents scaffold <repo-dir> [name] [flags]
```
--attribution this repo requires AI disclosure: install the Assisted-by commit hook and AGENTS.md policy section
-h, --help help for scaffold
--private leave no tracked trace: .work.local/ only, excluded via git info/exclude
--private leave no tracked trace: .abcd/.work.local/ only, excluded via git info/exclude
```

### SEE ALSO
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Every command is run as `ferry <command>` (e.g. `ferry init`).
| `restore` | Reverse ferry's changes, returning the machine to its pre-ferry state from an automatic backup. |
| `export` | Write a portable, secret-scanned `.zip` bundle of the repo's tracked shared files for an offline move. Prints the bundle's reproducible SHA256 — exporting the same tracked sources always yields the same digest (no timestamps or randomness are bundled), so the digest can be recomputed and verified with `import --expect-sha256`. Never includes secrets, `~/.ssh`, or the local layer (unless `--include-local`). |
| `import` | Ingest a bundle into a fresh config repo (`~/.config/ferry/repo` by default), validate it fully, then write ferry's config. Refuses a non-empty target. `--expect-sha256 <hash>` verifies integrity. |
| `agents scaffold` | Set up a project repo for AI-agent work from the templates in the config repo's `agents/` area: an `AGENTS.md` router, `CLAUDE.md`/`GEMINI.md` bridges, and committed `.work/` handoff files. `--private` instead creates a `.work.local/` layer hidden via `.git/info/exclude` — for repos you don't own, it leaves zero tracked trace. `--attribution` (mutually exclusive with `--private`) instead installs a `prepare-commit-msg` hook that appends a kernel-style `Assisted-by:` trailer to agent-authored commits, for repos that require AI disclosure. Idempotent; never overwrites or repoints anything it didn't create. Works in linked worktrees and submodules. |
| `agents scaffold` | Set up a project repo for AI-agent work from the templates in the config repo's `agents/` area: an `AGENTS.md` router, `CLAUDE.md`/`GEMINI.md` bridges, and committed `.abcd/work/` memory files. `--private` instead creates a `.abcd/.work.local/` layer hidden via `.git/info/exclude` — for repos you don't own, it leaves zero tracked trace. `--attribution` (mutually exclusive with `--private`) instead installs a `prepare-commit-msg` hook that appends a kernel-style `Assisted-by:` trailer to agent-authored commits, for repos that require AI disclosure. Idempotent; never overwrites or repoints anything it didn't create. Works in linked worktrees and submodules. |
| `agents adopt` | One-time migration of an existing symlink-based instruction setup into the config repo: imports the source files (never modifying the source directory), then swaps each `$HOME` bridge symlink for a ferry-managed copy in a single journalled transaction — any failure rolls back and the symlinks return. Refuses directory-level bridges with exact instructions rather than writing through them. |
| `version` | Print the version; `--verbose` adds the Go version and platform. |

Expand Down
6 changes: 3 additions & 3 deletions internal/agents/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
// reverses every deploy from the same file baseline as any other domain.
//
// The package also carries the two repo-onboarding operations: Scaffold (stamp
// the standard AGENTS.md router, .work/ skeleton, and in-repo bridge symlinks
// into a project repo — in-repo symlinks are the project's own and are never
// deployed to $HOME) and the adopt helpers (import an existing symlink-based
// the standard AGENTS.md router, .abcd/work/ skeleton, and in-repo bridge
// symlinks into a project repo — in-repo symlinks are the project's own and are
// never deployed to $HOME) and the adopt helpers (import an existing symlink-based
// instruction directory into the config repo and retire its $HOME bridge
// symlinks in favour of ferry-managed copies).
package agents
Loading
Loading