8000 ROADMAP M1: run data moves to .aladdin/ with a .agentic/ fallback, ALADDIN_* aliases, aloop layout by adeelahmad · Pull Request #21 · adeelahmad/aloop · GitHub
[go: up one dir, main page]

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: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ tag in lockstep. Tag releases as `vMAJOR.MINOR.PATCH`.
## [Unreleased]

### Changed
- **Run data moves to `.aladdin/`** (ROADMAP M1). Fresh projects keep transcripts, budgets,
the ledger, logs, state, host records and task worktrees under `.aladdin/`, next to
`config.yaml`; `.aladdin/.gitignore` (written by the plugin) keeps everything but
`config.yaml` out of git. A project that already has `.agentic/` keeps using it until
`aloop layout migrate` moves it (refused while worker worktrees are live); `aloop layout
show` says which dir is live and `aloop layout check` fails unless the run data is
git-ignored. Every `AGENTIC_<KEY>` env var and settings key accepts `ALADDIN_<KEY>`
(`AGENTIC_` wins when both are set). The gates and `budget` find the task contract in
either dir, so a supervisor that writes the old literal path is still understood. The
worktree-local markers (`.agentic/task.env`, `budget-exceeded`, `scaffold-symbols`) keep
their name for now. Test: `scripts/test/layout.test.py`; every suite runs on the new layout.
- **Workers append their `output.md` block before `selfcheck`** (RED/SCAFFOLD/GREEN personas,
agents and pipeline sources). Reason: the soft-limit line said "run selfcheck, append your
report", so workers self-checked first and were blocked for a missing report block: 4 of
Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ shellcheck: ## Lint gate scripts (skipped with a warning if shellcheck is absent
.PHONY: pycheck
pycheck: ## Byte-compile the Python hook scripts
@python3 -m py_compile plugin/bin/budget plugin/bin/stats plugin/bin/aloop-init plugin/bin/gate-commit-author plugin/bin/_paths.py \
plugin/bin/_usage.py plugin/bin/_events.py plugin/bin/events plugin/bin/intent plugin/bin/lessons plugin/bin/ids plugin/bin/targets plugin/bin/impact plugin/bin/timebox plugin/bin/sweep plugin/bin/capabilities plugin/bin/models plugin/bin/_routes.py plugin/bin/host plugin/bin/_host.py plugin/bin/config plugin/bin/_config.py plugin/bin/_lsp.py scripts/test/fixtures/fake-lsp.py plugin/bin/_timebox.py plugin/bin/host-adapter plugin/bin/install \
plugin/bin/_usage.py plugin/bin/_events.py plugin/bin/events plugin/bin/intent plugin/bin/lessons plugin/bin/ids plugin/bin/targets plugin/bin/impact plugin/bin/timebox plugin/bin/sweep plugin/bin/capabilities plugin/bin/models plugin/bin/_routes.py plugin/bin/host plugin/bin/_host.py plugin/bin/config plugin/bin/_config.py plugin/bin/layout plugin/bin/_lsp.py scripts/test/fixtures/fake-lsp.py plugin/bin/_timebox.py plugin/bin/host-adapter plugin/bin/install \
&& rm -rf plugin/bin/__pycache__ && echo "python ok"

.PHONY: test-hosts
Expand Down Expand Up @@ -106,6 +106,8 @@ test-hosts: ## Budget/worktree regression + Codex hooks emulation + OpenCode plu
python3 scripts/test/host-swap.test.py
python3 scripts/test/aladdin-cli.test.py
python3 scripts/test/site.test.py
python3 scripts/test/layout.test.py
plugin/bin/layout check
plugin/bin/host check
python3 scripts/test/targets-scope.test.py
python3 scripts/test/plan-render.test.py
Expand Down
7 changes: 4 additions & 3 deletions docs/OVERVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ The model can ignore a skill; it cannot ignore an exit code.
| `execution.log` | sprint | One-line state ledger |
| `sprintN/stats.md`, `sprintN/handoff.json`, `docs/agents/NEXT.md` | sprint | Harness-written stats (incl. the §4.10 metrics), the canonical handoff and its view |
| `docs/agents/intents/<id>.json` | project | Intent Contracts, with the raw words beside them |
| `.agentic/` | local | Transcripts, budgets, token ledger, worktree state, the `aladdin.event/1` stream (`logs/events.jsonl`), gate verdicts, host-swap record (git-ignored) |
| `.aladdin/` | local | Transcripts, budgets, token ledger, worktree state, the `aladdin.event/1` stream (`logs/events.jsonl`), gate verdicts, host-swap record; its own `.gitignore` keeps everything but `config.yaml` out of git. A project that still has `.agentic/` keeps using it until `aloop layout migrate` (`aloop layout show\|check`) |

## Where it stands

Expand Down Expand Up @@ -128,8 +128,9 @@ The model can ignore a skill; it cannot ignore an exit code.
- The default standards matrix targets Rust; other stacks need `standards.md` and gate edits.
- `refs` / `callers` / `callees` need a configured LSP server; without one they say so (exit 4).
- Hosts do not report the model's context window; `AGENTIC_CONTEXT_WINDOW` is the human's number.
- The on-disk layout keeps the pre-rename names (`.agentic/`, `AGENTIC_*`) for the migration
window; the move to `.aladdin/` is an open decision in ROADMAP M1.
- `AGENTIC_*` settings keys stay canonical; `ALADDIN_*` is an alias (`AGENTIC_` wins when both
are set). Worktree-local markers (`.agentic/task.env`, `budget-exceeded`, `scaffold-symbols`)
keep their name for now (ROADMAP M1).
- Measured runs: TheNoteBook plus the `make e2e-live` runs in ROADMAP §0; no live-session test in CI.

## The docs, and which ones are current
Expand Down
4 changes: 2 additions & 2 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ spec; this table is the plan. Versions are targets, not promises.
| **M0.6 — Gates fail closed** | v0.11.x | A gate that crashes (exit 1, e.g. an unbound variable) is a non-blocking hook error on Claude Code, so the action goes through. Make every gate trap unexpected errors into exit 2 with the reason, and add a conformance case per gate. Reason: the smoke run showed one real instance | done: `_failclosed.sh` on all 10 sub-agent gates + supervisor-scope inside a sprint; `scripts/test/fail-closed.test.py` (5 checks). Left fail-open on purpose: `gate-commit-author` and `gate-validate-artifact` outside a sprint, which see every session on the machine |
| **M0.7 — Supervisor-owned task contract** | v0.11.x | The contract lives in the main tree, `.agentic/state/tasks/<TASK_ID>.env`, and the dispatch prompt's first line names the task; gates and the time box find it from the host's transcript, a worktree `task.env` that disagrees blocks, and sub-agents may not Write/Edit `.agentic/state/` or `task.env`. Settled by a live probe: Claude Code's `isolation: "worktree"` makes `.claude/worktrees/agent-<id>` at dispatch, so a pre-written in-worktree contract was impossible there. Bash writes are guarded too (a command naming the contract with a write verb is blocked; a heuristic, so an obfuscated write still gets through). On hosts with no sub-agent transcript the worktree's `TASK_ID` (or its `.agentic/worktrees/<id>` path) picks the contract | done: `make conformance` (58 today) + `scripts/test/{budget-worktree,supervisor-scope}.test.py` |
| **M0.5 — Rename to aloop** | v0.11.0 | Plugin, marketplace, skill, CLI (`aloop`, `aloop init`), OpenCode plugin file and docs renamed; `agentic`, `agentic init`, `agentic-init` and `agentic bind` kept as aliases; OpenCode/Codex installs clean up pre-rename files. Data layout and settings keys unchanged (moved to M1). GitHub repo rename is the owner's call | done: `scripts/test/rename-compat.test.py` |
| **M1 — Trustworthy state** | v0.12 | Session 1: conformance fixtures around current behaviour, canonical IDs and the reference remap (§4.5); then move the data layout to the new name (`.agentic/` → `.aloop/`, `AGENTIC_*` → `ALOOP_*`) with a read-old fallback, proven by those fixtures | done except the layout move: §6 fixtures (`make conformance`, 58 checks incl. every false positive the live runs found) and canonical IDs + the reference remap (§4.5, `ids freeze`, `scripts/test/ids-integrity.test.py`) shipped; `.agentic/` → `.aloop/` deferred — §4.11 keeps `.agentic/` alongside `.aladdin/` for the migration window |
| **M1 — Trustworthy state** | v0.12 | Session 1: conformance fixtures around current behaviour, canonical IDs and the reference remap (§4.5); then move the data layout to the new name (`.agentic/` → `.aloop/`, `AGENTIC_*` → `ALOOP_*`) with a read-old fallback, proven by those fixtures | done: §6 fixtures (`make conformance`, 58 checks incl. every false positive the live runs found) and canonical IDs + the reference remap (§4.5, `ids freeze`, `scripts/test/ids-integrity.test.py`); **layout move shipped (Unreleased)**: run data lives in `.aladdin/` (chosen over `.aloop/`, 2026-10-18, because `config.yaml` already lives there and the product name is Aladdin), guarded by `.aladdin/.gitignore`; a project with `.agentic/` keeps using it until `aloop layout migrate`; `ALADDIN_<KEY>` is an alias of every `AGENTIC_<KEY>` env/setting (`AGENTIC_` wins when both are set); the gates find the task contract in either dir. Test: `scripts/test/layout.test.py`; every suite runs on the new layout. Left: the worktree-local markers (`.agentic/task.env`, `budget-exceeded`, `scaffold-symbols`) keep their name (reason: hosts and older sprints write them; rename with a read-old window in a later PR) |
| **M2 — Budgets that plan** | v0.13 | Sessions 2 and 4: budget semantics (§3.1–3.5), sprint envelope and admission control (§4.2), breach classes, failure envelope, grace rule, lesson candidates (§4.3) | done: §3.1–3.5 budget semantics, §4.2 sprint envelope + admission control (`budget admit`, `sweep`), §4.3 breach classes, failure envelope, grace rule and lesson candidates (tests: `budget-*.test.py`, `orchestrator-sweep.test.py`, `lesson-candidates.test.py`) |
| **M3 — Clean boundaries** | v0.14 | Session 3: canonical handoff, rotation and the resume rule (§4.4) | done: canonical `handoff.json` + NEXT.md view, rotation/compaction recorded from SessionStart, the resume rule (`stats resume-check`; tests: `context-boundary.test.py`, `handoff-resume.test.py`) |
| **M4 — Intent in, autonomy optional** | v0.15 | Session 5: Intent Contract, clarification policy, autonomous mode (§4.1) | done: Intent Contract (`bin/intent`), clarification policy, autonomous mode (tests: `intent-contract.test.py`); `aladdin "<intent>"` records it (§4.11) |
Expand Down Expand Up @@ -275,7 +275,7 @@ No extra model calls are made just for telemetry.
- `/agentic-agile:init`
- the `agentic` command
- the `agentic-agile:*` agent prefixes
- `.agentic/` alongside `.aladdin/`
- `.agentic/` alongside `.aladdin/` (read as the run-data dir until `aloop layout migrate`; M1)
- **README reordered, product first:**
1. Intent is all you need
2. Demo
Expand Down
1 change: 1 addition & 0 deletions docs/TRACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ Status of every requirement in [ROADMAP.md](ROADMAP.md), in the four states §8
| 4.10 | Context-window share (peak / `AGENTIC_CONTEXT_WINDOW`) | IMPLEMENTED_TESTED | `scripts/test/metrics.test.py` |
| 4.11 | Entry points: `aladdin` CLI (intent, run, status, resume, report, semantic queries) and `/aladdin` | IMPLEMENTED_TESTED | `scripts/test/aladdin-cli.test.py` |
| 4.11 | Compatibility aliases (`agentic`, `/aloop`, `.agentic/` alongside `.aladdin/`) | IMPLEMENTED_TESTED | `scripts/test/rename-compat.test.py` |
| M1 | Run data in `.aladdin/` (guarded by its `.gitignore`), `.agentic/` read as legacy, `aloop layout show\|check\|migrate`, `ALADDIN_*` aliases, contract found in either dir | IMPLEMENTED_TESTED | `scripts/test/layout.test.py` |
| 4.11 | README reordered product-first (intent → demo → TDD agents → loop → gates → install → hosts → evidence → audit → architecture → limitations) | IMPLEMENTED_UNTESTED | prose; its claims cite ROADMAP §0 runs and `make e2e-live` |
| 4.11 | Site (`docs/index.html`, GitHub Pages from `/docs`) with the lamp motif, RED explainer and audit tree; numbers sourced from §0 | IMPLEMENTED_TESTED | `scripts/test/site.test.py` |
9 changes: 6 additions & 3 deletions plugin/bin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,22 @@ never calls them directly. Shared helpers live in `_gatelib.sh`.
Transcripts hooks (`transcripts`) ALWAYS exit `0` — they must never block an agent.

## Per-task contract
Gates read the supervisor's contract `<main tree>/.agentic/state/tasks/<TASK_ID>.env`
Gates read the supervisor's contract `<main tree>/.aladdin/state/tasks/<TASK_ID>.env`
(`.agentic/...` in a legacy project; both dirs are searched)
(written before dispatch; the dispatch prompt's first line `TASK_ID: <id>` names it):
`TASK_ID, ATTEMPT, AGENT_ROLE, SCOPE_GLOBS, SCAFFOLD_SYMBOLS, BASE_REF, STORY_DIR,
BUDGET_*`. A worktree `.agentic/task.env` is a fallback and must match the contract when
both exist. Parsed, never sourced. Real env overrides. Store paths are NOT part of the contract:
`_paths.sh` / `_paths.py` fix them (`<main tree>/.agentic/{transcripts,budget,ledger,logs,state}`,
`_paths.sh` / `_paths.py` fix them (`<main tree>/.aladdin/{transcripts,budget,ledger,logs,state}`,
or `.agentic/` where a project still has one — `aloop layout show|check|migrate`;
`docs/agents/{defaults.md,NEXT.md}`). A missing backend (md-db /
ctx-symbols) → WARN + grep fallback; never a silent pass.

## Gates (which hook fires each)
| script | event · matcher | checks | exit 2 when |
|--------|-----------------|--------|-------------|
| gate-supervisor-scope | PreToolUse · Write\|Edit\|MultiEdit\|Bash | MAIN agent (no `agent_type`) may not write production source mid-sprint, nor hand-author planning artifacts (stories/tasks/validate/plan/intake/standards.md — dispatch the activity); sub-agents (`agent_type` present) exempt | supervisor writes source / hand-writes a planner-owned artifact |
| gate-dispatch | PreToolUse · Agent\|Task | the MAIN agent's dispatch of an execution role opens with `TASK_ID: <id>` and that task's contract `.agentic/state/tasks/<id>.env` exists (repos with `.agentic/` only) | no TASK_ID line / contract not written yet |
| gate-dispatch | PreToolUse · Agent\|Task | the MAIN agent's dispatch of an execution role opens with `TASK_ID: <id>` and that task's contract `<run-data>/state/tasks/<id>.env` exists (repos with a run-data dir only) | no TASK_ID line / contract not written yet |
| gate-tooling | SubagentStart · exec roles + supervisor self-check | md-db + ctx-symbols installed (execution may not run grep-degraded); runs `ensure-tools --sync` first | a backend is missing and can't be built |
| gate-validate-artifact | PostToolUse · Write | md-db-validate the written artifact | artifact malformed |
| gate-red-verify | SubagentStop · red-worker | worktree-isolated; appended output.md block (validate_comms); every new test FAILS BY ASSERTION; no regression; diff = tests+shims | no/stale output.md block / shared-tree run / a new test passes / prod code / regression |
Expand Down Expand Up @@ -64,6 +66,7 @@ ctx-symbols) → WARN + grep fallback; never a silent pass.
| `ids` | canonical identity + referential integrity (ROADMAP §4.5): `freeze SPRINT_DIR` checks the structured references (story frontmatter ↔ dir, dirs ↔ stories.md, validate.md ↔ tasks.md headings, `split_from` → a retired task) and issues frozen UUIDv7 ids in `sprintN/ids.json`; a retired alias is never reused · `check` · `resolve ALIAS`. Run by `gate-stage2-complete`; events then carry `story_uid`/`task_uid`. |
| `targets` | semantic execution map (ROADMAP §4.6): the planner's `<story>/targets.json` — change targets and, with `tasks`, the whole semantic plan. `render STORY_DIR [--check]` writes tasks.md / validate.md / plan.md as deterministic views over it (the gate refuses a hand-edited view) · `check STORY_DIR` (run by `gate-stage2-complete`) · `target Tn STORY_DIR` (file:line, or `planned` for the shadow workspace) · `shadow` · `scope Tn STORY_DIR` (the diff scope gate-green-verify derives when SCOPE_GLOBS is unset) · `context Cn --budget N` (just the target's definition) · `refs\|callers\|callees` via the LSP server in `AGENTIC_LSP_COMMAND` (`_lsp.py`: references + call hierarchy); no server or a missing capability → exit 4, never guessed. Backend: ctx-symbols, else a definition regex flagged weaker. |
| `impact` | optional cross-project impact provider seam (ROADMAP §4.8): `query consumers\|rationale\|migration\|standards SUBJECT [--task]` runs `AGENTIC_IMPACT_PROVIDER` (defaults.md or env), keeps only results with a `source_ref`, saves them under `docs/agents/impact/` and emits `artifact.created`. No provider or a failing one → WARN, exit 0. Builds no index. |
| `layout` | the run-data dir (ROADMAP M1): `show` (which of `.aladdin/` / `.agentic/` is live and why) · `check` (exit 2 unless every run dir is git-ignored) · `migrate` (move `.agentic/` run data into `.aladdin/`, refused while worker worktrees are live; in `make test-hosts`) |
| `config` | the portable project config `.aladdin/config.yaml` (ROADMAP §4.9; sections budgets · context · semantic · models · provenance · memory · git, plus `budgets.roles.<role>`): `migrate` writes it from the current settings and renders `docs/agents/defaults.md` from it · `sync` re-renders defaults.md (SessionStart, `aloop-init --apply`) so bash readers see the same values · `check` validates (exit 2) · `show [--json]` effective value + source per setting. When it exists it is authoritative. |
| `capabilities` | the host capability matrix (`plugin/hosts/capabilities.json`: usage, compaction, live messaging, lifecycle, gate blocking; `unknown` = not advertised) · `boundary [HOST]` → rotate (default, the host's `/clear` or `/new`) or compact only when `AGENTIC_CONTEXT_BOUNDARY=compact` and advertised · `boundary --keep --reason` records the exception. SessionStart records `context.rotated` / `context.compacted`. |
| `models` | abstract model routes (ROADMAP §3.6): `resolve planning\|worker\|<role> [--host H] [--json]` → the host's id for the group's route (`strongest\|strong\|economical`, or a pinned id passed through; `--json` shows the route, conformance 18) · `routes` prints `hosts/routes.json`. `aloop install` renders from the same table. |
Expand Down
Loading
Loading
0