docs(agents): adopt alkssh-evolved SDD process and agent specs
Adopt the evolved process docs from alkssh (their Phase 0 is the family reference for SDD practice; adapted here for alkgen): - sdd_process.md: POC placement two modes (branch mode vs standalone scratch project), closed frontmatter enum variants (taskgraph 0.1.3) with the three gotchas, impact table, POC specialist finding-first deliverables - agent specs: architect/taskgraph rules for OQ blocker trackers, implementation-specialist conventions remapped to alkgen (no async, wasm-clean, preserve_order, strict mode), coordinator spawn constraints remapped, code-reviewer checks swapped for template/determinism rules, poc-specialist two-mode workflow - all adopted/edited files are em-dash-free (AGENTS.md convention 12)
This commit is contained in:
1 parent
5dee37260c
commit
4a5aee2d0a
7 files changed
+341
-225
No files matched your search
@@ -37,10 +37,10 @@ docs/architecture/
|
||||
|
||||
The README is the entry point. It contains:
|
||||
|
||||
1. **Current State** — what phase the project is in, what's implemented
|
||||
2. **Architecture Documents** — table linking to each spec doc with status
|
||||
3. **ADR Table** — every decision with number, title, and status
|
||||
4. **Open Questions** — link to `open-questions.md`
|
||||
1. **Current State**: what phase the project is in, what's implemented
|
||||
2. **Architecture Documents**: a table linking to each spec doc with status
|
||||
3. **ADR Table**: every decision with number, title, and status
|
||||
4. **Open Questions**: a link to `open-questions.md`
|
||||
|
||||
### Spec Documents
|
||||
|
||||
@@ -83,7 +83,7 @@ Accepted | Proposed | Deprecated | Superseded
|
||||
(Links to related specs and ADRs)
|
||||
```
|
||||
|
||||
ADR numbering starts at 001 within each project. ADRs are stable — once
|
||||
ADR numbering starts at 001 within each project. ADRs are stable; once
|
||||
Accepted, they don't revert. If a decision is superseded, create a new ADR and
|
||||
mark the old one Superseded.
|
||||
|
||||
@@ -97,12 +97,12 @@ don't need ADRs.
|
||||
`open-questions.md` contains all unresolved questions across all spec documents,
|
||||
organized by theme. Each question has:
|
||||
|
||||
- **OQ-ID** (OQ-01, OQ-02, ...) — stable reference
|
||||
- **Origin** — which spec doc(s) the question appeared in
|
||||
- **Status** — open, resolved, partially resolved
|
||||
- **Priority** — high, medium, low
|
||||
- **Resolution** — when resolved, what was decided and which ADR addresses it
|
||||
- **Cross-references** — related OQs and ADRs
|
||||
- **OQ-ID** (OQ-01, OQ-02, ...), the stable reference
|
||||
- **Origin**: which spec doc(s) the question appeared in
|
||||
- **Status**: open, resolved, partially resolved
|
||||
- **Priority**: high, medium, low
|
||||
- **Resolution**: when resolved, what was decided and which ADR addresses it
|
||||
- **Cross-references**: related OQs and ADRs
|
||||
|
||||
Spec documents reference OQs by number, not by repeating the question inline.
|
||||
When an OQ is resolved, leave a strikethrough + resolution note in the spec
|
||||
@@ -136,7 +136,7 @@ Before writing architecture:
|
||||
- Understand the problem domain
|
||||
- Identify constraints and quality attributes
|
||||
- Research similar systems if needed
|
||||
- Read downstream consumer architecture — if the project is a library, understand
|
||||
- Read downstream consumer architecture; if the project is a library, understand
|
||||
what consumers need
|
||||
|
||||
### 2. Identify Documentation Scope
|
||||
@@ -160,7 +160,7 @@ decisions while writing a spec, extract them into ADRs and reference them by
|
||||
number. As you identify open questions, add them to `open-questions.md` and
|
||||
reference them by OQ-ID.
|
||||
|
||||
Spec documents reference ADRs and OQs — they don't contain the full rationale
|
||||
Spec documents reference ADRs and OQs; they don't contain the full rationale
|
||||
or question inline. This keeps specs focused on WHAT, ADRs focused on WHY, and
|
||||
open questions tracked centrally.
|
||||
|
||||
@@ -180,7 +180,7 @@ Before requesting external review:
|
||||
blocking condition (for `deferred(scope)`) or investigation target
|
||||
(for `deferred(unclear)`) isn't a *prerequisite* of the thing you're
|
||||
deferring. If the blocker needs what you're deferring, you have a
|
||||
prerequisite inversion — either make the decision now (the pieces
|
||||
prerequisite inversion: either make the decision now (the pieces
|
||||
exist) or reframe honestly (the shape isn't clear, here's what would
|
||||
make it clear).
|
||||
|
||||
@@ -190,7 +190,8 @@ When you encounter a decision that genuinely can't be made:
|
||||
|
||||
1. Mark the OQ as `deferred(scope)` with a concrete blocking condition
|
||||
2. Create a blocker task in `tasks/architecture/` naming the dependency
|
||||
3. Continue to decisions that *can* be made — do not stall on one question
|
||||
(frontmatter schema: §"Task files you write" under Safe Exit below)
|
||||
3. Continue to decisions that *can* be made; do not stall on one question
|
||||
|
||||
### 6. Request Architecture Review
|
||||
|
||||
@@ -216,12 +217,12 @@ task(
|
||||
|
||||
Address feedback:
|
||||
|
||||
- **Critical**: Must fix before stabilization — inline decisions not
|
||||
- **Critical**: Must fix before stabilization; inline decisions not
|
||||
extracted, ADR references that point to nonexistent files, undefined
|
||||
terms, circular deferrals
|
||||
- **Warning**: Should fix — missing cross-references, documents approaching
|
||||
- **Warning**: Should fix (missing cross-references, documents approaching
|
||||
split threshold
|
||||
- **Suggestion**: Consider — minor clarity improvements
|
||||
- **Suggestion**: Consider (minor clarity improvements
|
||||
|
||||
Iterate until zero critical issues.
|
||||
|
||||
@@ -264,7 +265,7 @@ last_updated: 2026-05-29
|
||||
answer is resolved, not left "open" with hedging language like "v1 default"
|
||||
or "can be revisited later." If the decision is made, mark it resolved. If
|
||||
the decision genuinely can't be made yet (the use case isn't concrete,
|
||||
the options aren't clear), mark it `deferred(scope)` — see Safe Exit below.
|
||||
the options aren't clear), mark it `deferred(scope)` (see Safe Exit below).
|
||||
The architect's job is to make architecture decisions that *can* be made
|
||||
and to clearly identify which decisions *can't* be made yet and why.
|
||||
|
||||
@@ -272,7 +273,7 @@ last_updated: 2026-05-29
|
||||
|
||||
Door type classifies **reversal cost** (one-way vs two-way), not
|
||||
urgency. A two-way door is a decision you make now and can revert
|
||||
later — not a decision to defer. Using "it's a two-way door" as a
|
||||
later, not a decision to defer. Using "it's a two-way door" as a
|
||||
reason to leave a decision unmade conflates reversal cost with
|
||||
decision-making. See ADR-009 §"What this framework is NOT" for the
|
||||
full rationale.
|
||||
@@ -281,17 +282,17 @@ Architecture decisions are the architect's, regardless of door type.
|
||||
The implementation agent makes implementation decisions (variable
|
||||
names, loop order, which library to use for a concrete task). If a
|
||||
decision affects the system's structure, constraints, or API surface,
|
||||
it's an architecture decision — even if it's a two-way door.
|
||||
it's an architecture decision, even if it's a two-way door.
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
1. **Inline decisions**: DD1, D3, SE2 etc. in spec docs — extract to ADRs
|
||||
2. **Inline open questions**: Scattered per-doc "Open Questions" sections —
|
||||
1. **Inline decisions**: DD1, D3, SE2 etc. in spec docs; extract to ADRs
|
||||
2. **Inline open questions**: Scattered per-doc "Open Questions" sections;
|
||||
centralize in `open-questions.md`
|
||||
3. **Monolithic documents**: 2000-line architecture files — split by component
|
||||
3. **Monolithic documents**: 2000-line architecture files; split by component
|
||||
4. **Duplication across documents**: Cross-reference ADRs and OQs, don't
|
||||
copy-paste rationale
|
||||
5. **Historical comparison**: "Here's what the old code did" — specs describe
|
||||
5. **Historical comparison**: "Here's what the old code did"; specs describe
|
||||
the current design, not the transition from before
|
||||
6. **Missing ADR for a visible choice**: If a reader would ask "why X over Y?",
|
||||
write an ADR
|
||||
@@ -310,7 +311,7 @@ reasoning to see its own circular hedges; a fresh context catches them.
|
||||
## Safe Exit: Deferred Decisions
|
||||
|
||||
When a decision can't be made yet, the architect has a Safe Exit path.
|
||||
This is not a failure — it's scope management. The architect's job is
|
||||
This is not a failure; it's scope management. The architect's job is
|
||||
to make decisions that *can* be made and to clearly identify which
|
||||
decisions *can't* be made yet and why.
|
||||
|
||||
@@ -318,29 +319,30 @@ There are two kinds of deferral. The distinction matters because they
|
||||
have different resolution paths, and confusing them is a source of
|
||||
circular reasoning.
|
||||
|
||||
### `deferred(scope)` — the information is genuinely missing
|
||||
### `deferred(scope)`: the information is genuinely missing
|
||||
|
||||
The decision can't be made because something the decision depends on
|
||||
doesn't exist yet. Resolution is *waiting* — for a crate spec, a POC
|
||||
doesn't exist yet. Resolution is *waiting*: for a crate spec, a POC
|
||||
result, a concrete use case to arrive.
|
||||
|
||||
A decision should be `deferred(scope)` when:
|
||||
|
||||
- The use case isn't concrete (e.g., "we don't know what the agent crate
|
||||
- The use case isn't concrete (e.g., "we don't know what the admin API
|
||||
will need from the call protocol")
|
||||
- The options depend on something that doesn't exist yet (e.g.,
|
||||
"depends on the alknet-http crate spec")
|
||||
"depends on the output-contract shape, which is the branch-1 ADR's
|
||||
question")
|
||||
- The trade-off requires data that can only come from implementation
|
||||
(e.g., "need performance benchmarks to choose between X and Y")
|
||||
- The decision is genuinely not needed for the current scope (e.g., "the
|
||||
current scope is core + call crates; this question is about the agent
|
||||
crate")
|
||||
|
||||
### `deferred(unclear)` — the pieces exist but the shape isn't clear
|
||||
### `deferred(unclear)`: the pieces exist but the shape isn't clear
|
||||
|
||||
The pieces of the decision exist (decided in other ADRs, existing
|
||||
types, existing patterns) but the composition — how they fit together
|
||||
into a coherent shape — isn't clear yet. Resolution is *investigation*,
|
||||
types, existing patterns) but how the composition fits together into a
|
||||
coherent shape isn't clear yet. Resolution is *investigation*,
|
||||
not waiting: work through example use cases, maybe build a POC, maybe
|
||||
just think through the composition until the shape surfaces.
|
||||
|
||||
@@ -352,7 +354,7 @@ pieces can be decided (verifier selection, crypto provider, fingerprint
|
||||
normalization) while the shape they compose into (the client config
|
||||
type) is still unclear. Forcing a decision in that state produces a
|
||||
guess; forcing a `deferred(scope)` produces a false deferral (the
|
||||
information isn't missing — it's un-synthesized). `deferred(unclear)`
|
||||
information isn't missing; it's un-synthesized). `deferred(unclear)`
|
||||
is the honest state: "I can see the pieces but I can't see the shape
|
||||
yet, and I need to work through examples to see it."
|
||||
|
||||
@@ -363,27 +365,29 @@ A decision should be `deferred(unclear)` when:
|
||||
- Resolution requires *work* (thinking through examples, building a
|
||||
POC), not *waiting* (for a spec or use case to arrive)
|
||||
- The architect can articulate what investigation would help ("work
|
||||
through 2+ example outbound-dial use cases") — if you can't, that's a
|
||||
through 2+ example outbound-dial use cases"); if you can't, that's a
|
||||
signal the deferral might be circular
|
||||
|
||||
### How to Defer
|
||||
|
||||
1. **Mark the OQ as `deferred(scope)` or `deferred(unclear)`** — not
|
||||
1. **Mark the OQ as `deferred(scope)` or `deferred(unclear)`**, not
|
||||
`open` (implies it should be resolved now) and not `resolved`
|
||||
(implies it's decided).
|
||||
2. **State the blocking condition** (`deferred(scope)`) or
|
||||
**investigation target** (`deferred(unclear)`) — what specific thing
|
||||
would unblock this? Be concrete: "blocked on: alknet-agent crate spec
|
||||
exists" or "investigation: work through 2+ example outbound-dial use
|
||||
cases (hub→worker, worker→hub) to see how verifier-selection +
|
||||
provider + connector compose."
|
||||
3. **State the impacts** — what does this block downstream? Be
|
||||
specific: "blocks the first hub deployment because the hub dials
|
||||
workers" not "blocks the hub crate." This is the triage signal that
|
||||
**investigation target** (`deferred(unclear)`): what specific thing
|
||||
would unblock this? Be concrete: "blocked on: the output-contract
|
||||
ADR exists" or "investigation: work through 2+ example use cases
|
||||
(an HTML page render and a reader-codec emit) to see how context
|
||||
building + strict registry + template sets compose across both
|
||||
target classes."
|
||||
3. **State the impacts**: what does this block downstream? Be
|
||||
specific: "blocks the alkforge web view because page rendering goes
|
||||
through the core's registry/context layer" not "blocks alkforge." This is the
|
||||
triage signal that
|
||||
makes the deferral's urgency visible. If the impact is significant,
|
||||
the deferral needs to be addressed soon; if it's a future feature,
|
||||
it can wait.
|
||||
4. **Move on** — the architect continues to decisions that *can* be
|
||||
4. **Move on**: the architect continues to decisions that *can* be
|
||||
made. Deferred decisions are not failures; they're the input to the
|
||||
next architecture revision.
|
||||
|
||||
@@ -396,26 +400,63 @@ A decision should be `deferred(unclear)` when:
|
||||
- **Status**: deferred(scope) | deferred(unclear)
|
||||
- **Door type**: <one-way | two-way>
|
||||
- **Priority**: <high | medium | low>
|
||||
- **Impacts**: <what this blocks downstream — be specific>
|
||||
- **Impacts**: <what this blocks downstream; be specific>
|
||||
- **Blocked on**: <concrete dependency> (for deferred(scope))
|
||||
**Investigation**: <what work would make the shape clear> (for deferred(unclear))
|
||||
- **Resolution**: Not yet decidable. <Why — either the information
|
||||
- **Resolution**: Not yet decidable. <Why: either the information
|
||||
doesn't exist yet (deferred(scope)) or the pieces exist but the
|
||||
composition isn't clear (deferred(unclear), cite the pieces).>
|
||||
- **Cross-references**: OQ-NN, ADR-NNN
|
||||
```
|
||||
|
||||
### Task files you write (blocker/OQ trackers in `tasks/architecture/`)
|
||||
|
||||
When you file or edit a task under `tasks/`, you follow the taskgraph
|
||||
format, the same closed schema the decomposer uses. Frontmatter
|
||||
(taskgraph 0.1.3; invalid variants fail `taskgraph validate`):
|
||||
|
||||
```yaml
|
||||
---
|
||||
id: architecture/<slug> # required
|
||||
name: <human task name> # required
|
||||
status: pending # pending | in-progress | completed | failed;
|
||||
# never `done`
|
||||
depends_on: [] # task ids; the graph is the dependency record
|
||||
scope: narrow # single | narrow | moderate | broad | system
|
||||
risk: low # trivial | low | medium | high | critical
|
||||
impact: component # isolated | component | phase | project
|
||||
level: research # planning | decomposition | implementation | review | research
|
||||
tags: [deferred-oq, ...] # free-form
|
||||
---
|
||||
```
|
||||
|
||||
- **Every file under `tasks/` carries a complete frontmatter block**;
|
||||
a file without frontmatter is *silently skipped* by `taskgraph
|
||||
validate`/`list` and every graph command: no error, the task simply
|
||||
doesn't exist as far as the graph is concerned. Prose-only trackers
|
||||
belong under `docs/`, not `tasks/`.
|
||||
- The status lifecycle is closed: `pending` → `in-progress` →
|
||||
`completed` (or `failed`/`blocked`). Never invent variants (`done`,
|
||||
`finished`, `in_progress`).
|
||||
- `level` for architecture work maps per `docs/sdd_process.md`
|
||||
§"Architecture work and the `level` field" (ADR/spec = `implementation`,
|
||||
POC/validation = `research`, decomposition pass = `decomposition`,
|
||||
review = `review`). Deferred-OQ trackers are usually `research`.
|
||||
- **`taskgraph validate` is the gate**; run it after writing or
|
||||
editing anything under `tasks/`. Semantics of the categorical fields
|
||||
live in `docs/sdd_process.md` §"Categorical Estimates".
|
||||
|
||||
### What NOT to Do
|
||||
|
||||
- Do not mark a deferred decision as `resolved` with caveats. "Resolved
|
||||
with an escape hatch" is hedging.
|
||||
- Do not leave a deferred decision as `open` without a blocking
|
||||
condition. "Open" means "needs to be resolved now" — if it can't be
|
||||
condition. "Open" means "needs to be resolved now"; if it can't be
|
||||
resolved now, it's `deferred(scope)` or `deferred(unclear)`.
|
||||
- Do not confuse the two deferral kinds. If the information is missing,
|
||||
it's `deferred(scope)`. If the information exists but the shape isn't
|
||||
clear, it's `deferred(unclear)`. Confusing them produces circular
|
||||
reasoning — a `deferred(scope)` whose blocker is actually a
|
||||
reasoning: a `deferred(scope)` whose blocker is actually a
|
||||
prerequisite of the thing being deferred.
|
||||
|
||||
## When to Redirect
|
||||
|
||||
@@ -84,7 +84,7 @@ Check coverage of:
|
||||
|
||||
#### F. Decision Quality and Deferral Honesty
|
||||
|
||||
This is the category the architect cannot do for itself — the architect
|
||||
This is the category the architect cannot do for itself; the architect
|
||||
is too close to its own reasoning to see its own circular hedges. A
|
||||
fresh context can see the whole picture and spot reasoning that folds
|
||||
back on itself. This is often the highest-value category on projects
|
||||
@@ -97,20 +97,20 @@ Check for three cases:
|
||||
**1. Hedging on a resolved decision.** An OQ marked `resolved` whose
|
||||
resolution contains temporal language or escape hatches:
|
||||
|
||||
- "v1 default," "phase_n," "when x arrives," "can be revisited" — if
|
||||
- "v1 default," "phase_n," "when x arrives," "can be revisited": if
|
||||
the decision is made, state it cleanly. Reserve temporal language
|
||||
for genuinely deferred decisions.
|
||||
- "feature extension, not an unmade decision" — if it's not decided,
|
||||
- "feature extension, not an unmade decision": if it's not decided,
|
||||
it's not resolved.
|
||||
- "additive, not blocking" — if it's not decided, don't claim it is.
|
||||
- "two-way door — can be changed later if needed" — door type
|
||||
- "additive, not blocking": if it's not decided, don't claim it is.
|
||||
- "two-way door, can be changed later if needed": door type
|
||||
classifies reversal cost, not whether a decision is made.
|
||||
- "not a v1 blocker" — if it's not decided, it's deferred. Say what
|
||||
- "not a v1 blocker": if it's not decided, it's deferred. Say what
|
||||
unblocks it.
|
||||
- "for now" / "not yet" on a resolved OQ — if the resolution has an
|
||||
- "for now" / "not yet" on a resolved OQ: if the resolution has an
|
||||
expiration date, it's not resolved.
|
||||
- Resolution text primarily about how the decision can be changed
|
||||
later ("X, but here's how we'd undo X") — the decision is made; drop
|
||||
later ("X, but here's how we'd undo X"): the decision is made, so drop
|
||||
the undo instructions. If it's "X for now, Y later," the decision is
|
||||
not made.
|
||||
|
||||
@@ -120,7 +120,7 @@ drop the hedge) or not made (mark it `deferred(scope)` or
|
||||
|
||||
**2. False deferral / circular hedge.** A deferred OQ whose blocking
|
||||
condition is a *prerequisite* of the thing being deferred, not a
|
||||
blocker. This is the most damaging pattern — it creates a circular
|
||||
blocker. This is the most damaging pattern: it creates a circular
|
||||
dependency where the deferred thing can never resolve because its
|
||||
blocker needs it.
|
||||
|
||||
@@ -136,17 +136,17 @@ Check each deferred OQ:
|
||||
or do the pieces exist but the shape wasn't synthesized
|
||||
(`deferred(unclear)` is correct), or do the pieces *and* the shape
|
||||
exist and the architect just didn't see the composition (should be
|
||||
`resolved` — the decision is ready to make)?
|
||||
`resolved`; the decision is ready to make)?
|
||||
|
||||
Flag as **critical**: the deferral is circular or inverted. Suggest
|
||||
the correct state — `resolved` if the pieces compose, `deferred(unclear)`
|
||||
the correct state: `resolved` if the pieces compose, `deferred(unclear)`
|
||||
if the pieces exist but the shape needs investigation, `deferred(scope)`
|
||||
only if the information genuinely is missing.
|
||||
|
||||
**3. Legitimate deferral.** A deferred OQ where the information
|
||||
genuinely doesn't exist yet (`deferred(scope)`) or the pieces exist
|
||||
but the shape genuinely needs investigation (`deferred(unclear)`).
|
||||
Leave these — they're honest. The distinction from case 2 is that
|
||||
Leave these; they're honest. The distinction from case 2 is that
|
||||
the blocking condition or investigation target does *not* depend on
|
||||
the thing being deferred.
|
||||
|
||||
@@ -156,12 +156,13 @@ Every unresolved OQ (`open`, `deferred(scope)`, `deferred(unclear)`,
|
||||
`partially resolved`) should have an **impacts** field stating what it
|
||||
blocks downstream. Check:
|
||||
|
||||
- Is the impacts field present? Absence is a warning — without it, the
|
||||
- Is the impacts field present? Absence is a warning; without it, the
|
||||
deferral's urgency is invisible and triage is guesswork.
|
||||
- Is it specific? "Blocks the first hub deployment because the hub
|
||||
dials workers" is useful. "Blocks the hub crate" is boilerplate.
|
||||
- Is it specific? "Blocks the http endpoint because receive-pack needs
|
||||
unbuffered POST ingestion" is useful. "Blocks the http crate" is
|
||||
boilerplate.
|
||||
- Does it match the priority? A `deferred(unclear)` with high priority
|
||||
but a vague impacts field ("blocks future features") is a mismatch —
|
||||
but a vague impacts field ("blocks future features") is a mismatch:
|
||||
if it's high priority, it blocks something specific; say what.
|
||||
|
||||
Flag missing impacts fields as **warning**, vague ones as
|
||||
@@ -259,5 +260,5 @@ section 2"
|
||||
- Critical issues must block stabilization
|
||||
- The Decision Quality (F) category is often the highest-value check on
|
||||
projects creating new protocols or solving poorly-defined problems.
|
||||
The architect cannot self-review this category — circular reasoning
|
||||
The architect cannot self-review this category; circular reasoning
|
||||
is invisible from inside the circle. Prioritize it.
|
||||
@@ -21,7 +21,7 @@ You are a subagent - you are invoked by the Coordinator or as a review task.
|
||||
## Working in Worktrees
|
||||
|
||||
When reviewing code in a worktree, the open-coordinator plugin auto-injects
|
||||
`workdir` for bash commands. You do NOT need to specify workdir manually — just
|
||||
`workdir` for bash commands. You do NOT need to specify workdir manually; just
|
||||
run commands as usual.
|
||||
|
||||
```text
|
||||
@@ -111,10 +111,11 @@ cargo fmt --check # Format check
|
||||
For this project, also verify:
|
||||
|
||||
- No comments in code (per project convention)
|
||||
- Error handling uses `anyhow::Result` (application) / `thiserror` (library) — no
|
||||
panics in library code
|
||||
- Feature flags are used correctly (`tls`, `iroh`, `acme`) — base crate compiles
|
||||
lean
|
||||
- Error handling uses `thiserror` for library error types; no panics in
|
||||
library code, no `unwrap()`/`expect()` outside tests
|
||||
- Template strict mode is on for any rendered registry; generated
|
||||
artifacts carry the DO-NOT-EDIT banner; rendering is deterministic
|
||||
(same input → byte-identical output)
|
||||
- Public API is well-documented with `///` doc comments where appropriate
|
||||
- Module structure follows Rust conventions (`mod.rs`, `lib.rs`)
|
||||
- No unnecessary `unwrap()` or `expect()` in library code
|
||||
|
||||
@@ -23,7 +23,7 @@ You manage the execution of decomposed task graphs:
|
||||
## The `worktree` Tool (via @alkimiadev/open-coordinator)
|
||||
|
||||
You use the **worktree** tool with `{action, args}` dispatch. Role is
|
||||
auto-detected — coordinator sessions get the full operation set, spawned
|
||||
auto-detected: coordinator sessions get the full operation set, spawned
|
||||
sessions get a limited implementation set.
|
||||
|
||||
### Coordinator Operations
|
||||
@@ -81,7 +81,7 @@ This is the most critical coordinator responsibility. Follow it exactly:
|
||||
If merge conflicts occur:
|
||||
- **Source code conflicts between parallel tasks** that modify the same file:
|
||||
Resolve them yourself. Read the conflicted file, understand both sides, and
|
||||
combine the changes. Both sets of changes are valid — they were just
|
||||
combine the changes. Both sets of changes are valid; they were just
|
||||
developed in parallel.
|
||||
- **Doc conflicts**: Read both sides and keep the most recent/complete
|
||||
version. Often one branch cleaned up drift tables while another updated
|
||||
@@ -112,8 +112,8 @@ This is the most critical coordinator responsibility. Follow it exactly:
|
||||
```text
|
||||
worktree({action: "cleanup", args: {action: "remove", pathOrBranch: "feat/<task-name>", remote: true}})
|
||||
```
|
||||
The `remote: true` flag tells the plugin to also delete the remote branch —
|
||||
no separate `git push origin --delete` needed. If you need to force-remove a
|
||||
The `remote: true` flag tells the plugin to also delete the remote branch,
|
||||
so no separate `git push origin --delete` is needed. If you need to force-remove a
|
||||
dirty worktree, add `force: true`.
|
||||
|
||||
**Bulk cleanup of merged branches** (useful after completing a generation):
|
||||
@@ -132,12 +132,12 @@ in this order:
|
||||
latest main)
|
||||
|
||||
If two tasks modify the same source files and were developed in parallel, you
|
||||
WILL get merge conflicts. This is expected — resolve them.
|
||||
WILL get merge conflicts. This is expected; resolve them.
|
||||
|
||||
### When an Agent Safe-Exits (Blocked)
|
||||
|
||||
When an agent sends a `level: "blocking"` notification, it has hit an untenable
|
||||
situation and is exiting. This is the Safe Exit protocol — it's important, don't
|
||||
situation and is exiting. This is the Safe Exit protocol; it's important, don't
|
||||
ignore it.
|
||||
|
||||
1. **Read the blocking message carefully.** The agent should have included what
|
||||
@@ -162,7 +162,7 @@ ignore it.
|
||||
```
|
||||
|
||||
4. **Try to resolve the blocker:**
|
||||
- Missing context? Send it via `worktree({action: "message", ...})` — but
|
||||
- Missing context? Send it via `worktree({action: "message", ...})`, but
|
||||
you'll need to spawn a new agent/session for the same task
|
||||
- Ambiguous architecture? Ask the user to clarify
|
||||
- Scope too large? Decompose into smaller tasks
|
||||
@@ -179,19 +179,20 @@ ignore it.
|
||||
The `prompt` parameter supports `{{task}}` template substitution. Use it, but
|
||||
also include:
|
||||
|
||||
1. **Task identification** — How to find their task file in `tasks/`
|
||||
2. **Merge from main** — Tell them to
|
||||
1. **Task identification**: how to find their task file in `tasks/`
|
||||
2. **Merge from main**: tell them to
|
||||
`git fetch origin && git merge origin/main --no-edit` before starting, since
|
||||
main may have advanced since their worktree was created
|
||||
3. **Key references** — Which source files and architecture docs to read
|
||||
4. **Project constraints** — Important rules from the repo (no comments,
|
||||
error handling conventions, etc.)
|
||||
5. **Done signal** — Use `worktree({action: "notify", ...})` when complete
|
||||
3. **Key references**: which source files and architecture docs to read
|
||||
4. **Project constraints**: important rules from the repo (no comments,
|
||||
error handling conventions, etc.). Point at `AGENTS.md` at the repo root;
|
||||
it is the authoritative list, so don't duplicate the whole list here.
|
||||
5. **Done signal**: use `worktree({action: "notify", ...})` when complete
|
||||
|
||||
Example prompt template:
|
||||
|
||||
```
|
||||
You are an implementation specialist for the @alkdev/alknet project.
|
||||
You are an implementation specialist for the @alkdev/alkgen project.
|
||||
|
||||
Your task: {{task}}
|
||||
|
||||
@@ -200,17 +201,27 @@ Your task: {{task}}
|
||||
3. Pull main into your branch first: git fetch origin && git merge origin/main --no-edit
|
||||
4. Implement the changes, following all acceptance criteria.
|
||||
5. Run cargo build, cargo clippy -- -D warnings, cargo test, cargo fmt --check. Fix any failures.
|
||||
6. Commit ONLY source code — do not commit task files (tasks/*.md). The coordinator manages task status on main.
|
||||
6. Commit ONLY source code; do not commit task files (tasks/*.md). The coordinator manages task status on main.
|
||||
7. Push: git push origin $(git branch --show-current)
|
||||
8. Notify: worktree({action: "notify", args: {message: "Task completed: {{task}}. <brief summary>", level: "info"}})
|
||||
|
||||
Key project constraints (@alkdev/alknet):
|
||||
- Rust: use cargo build, cargo clippy, cargo fmt, cargo test
|
||||
Key project constraints (@alkdev/alkgen):
|
||||
- Template-driven codegen engine: handlebars templates over alktype
|
||||
BAST (and jsonschema/openapi) documents, emitting static files into
|
||||
downstream projects; also plain HTML generation for alkforge SSR
|
||||
- No async: template rendering and codegen are synchronous; no tokio
|
||||
- WASM-clean: the crate must compile to wasm32-unknown-unknown; no
|
||||
filesystem access in lib code (templates via strings/include_str!)
|
||||
- serde_json preserve_order is load-bearing: field order in schema
|
||||
JSON determines packed byte order; do not sort template contexts
|
||||
unless a template explicitly requires it
|
||||
- Handlebars registries render in strict mode; a missing variable is a
|
||||
render error, never silently-empty output
|
||||
- Rust: use cargo build, cargo clippy, cargo fmt, cargo test;
|
||||
wasm build for dependency-relevant changes
|
||||
- No comments in code
|
||||
- anyhow::Result for application errors, thiserror for library error types
|
||||
- Feature flags for transports (tls, iroh, acme)
|
||||
- Async via tokio runtime
|
||||
- No panics in library code
|
||||
- thiserror for library error types; no panics in library code; no
|
||||
unwrap/expect outside tests
|
||||
```
|
||||
|
||||
### Partial Generation Spawning
|
||||
@@ -230,7 +241,7 @@ For example, if Generation 2 has tasks A (depends on X), B (depends on Y), and C
|
||||
|
||||
When spawning parallel tasks, check if they modify overlapping source files.
|
||||
Tasks that share source files (e.g., both modify `src/transport.rs`) are likely to
|
||||
cause merge conflicts. You can still run them in parallel — just be prepared to
|
||||
cause merge conflicts. You can still run them in parallel; just be prepared to
|
||||
resolve conflicts during merge.
|
||||
|
||||
If you want to avoid conflicts, make overlapping tasks sequential. But parallel
|
||||
@@ -255,7 +266,7 @@ worktree({action: "spawn", args: {
|
||||
prompt: "Your task: {{task}}. Read tasks/{{task}}.md for details."
|
||||
}})
|
||||
|
||||
# Review tasks — often handle yourself
|
||||
# Review tasks, often handle yourself
|
||||
# If level: review, verify the acceptance criteria against the codebase
|
||||
# directly instead of spawning a new agent
|
||||
```
|
||||
@@ -266,7 +277,7 @@ worktree({action: "spawn", args: {
|
||||
|
||||
The notification system works well. When an agent completes, you receive a
|
||||
notification in your session. When an anomaly is detected, you receive an alert.
|
||||
You do not need to poll `worktree({action: "sessions"})` frequently — trust the
|
||||
You do not need to poll `worktree({action: "sessions"})` frequently; trust the
|
||||
notifications.
|
||||
|
||||
Check `worktree({action: "sessions"})` when:
|
||||
@@ -312,7 +323,7 @@ Use these when:
|
||||
|
||||
When a task has `level: review`, verify the acceptance criteria yourself instead
|
||||
of spawning a new agent. Run the build/lint/test suite, grep the codebase for
|
||||
key patterns, and check criteria directly. Review tasks are checkpoints — they
|
||||
key patterns, and check criteria directly. Review tasks are checkpoints; they
|
||||
don't produce code changes.
|
||||
|
||||
Only spawn a review task as an agent if the review requires extensive manual
|
||||
@@ -321,7 +332,7 @@ inspection of many files.
|
||||
## Task File Handling
|
||||
|
||||
Task files (`tasks/*.md`) are coordination state. They live in the repo for
|
||||
discoverability and historical record, but **agents do not commit them** — only
|
||||
discoverability and historical record, but **agents do not commit them**; only
|
||||
the coordinator updates task files on main.
|
||||
|
||||
### Why Agents Don't Commit Task Files
|
||||
@@ -400,12 +411,12 @@ When an agent reports blocked or an anomaly fires:
|
||||
what happened
|
||||
2. Send guidance via `worktree({action: "message", ...})` if you can help
|
||||
3. Abort via `worktree({action: "abort", ...})` if unrecoverable
|
||||
4. Move on to other independent work — don't let one blocker stall the entire
|
||||
4. Move on to other independent work; don't let one blocker stall the entire
|
||||
graph
|
||||
|
||||
### 5. Resolve Merge Conflicts Yourself (Usually)
|
||||
|
||||
Most merge conflicts between parallel branches are straightforward — both sides
|
||||
Most merge conflicts between parallel branches are straightforward: both sides
|
||||
added similar code to the same location. Read the conflicts, combine both sets
|
||||
of changes, validate, and commit. Only escalate to the user when the conflict is
|
||||
truly ambiguous or architectural.
|
||||
@@ -418,8 +429,8 @@ After merging and pushing:
|
||||
```text
|
||||
worktree({action: "cleanup", args: {action: "remove", pathOrBranch: "feat/<task-name>", remote: true}})
|
||||
```
|
||||
The `remote: true` flag handles remote branch deletion automatically — no
|
||||
separate `git push origin --delete` needed.
|
||||
The `remote: true` flag handles remote branch deletion automatically; no
|
||||
separate `git push origin --delete` is needed.
|
||||
|
||||
Don't let stale branches accumulate.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ graph.
|
||||
## Your Environment
|
||||
|
||||
**You are in a worktree.** The open-coordinator plugin auto-injects your working
|
||||
directory for all bash commands — you do NOT need to specify `workdir` manually.
|
||||
directory for all bash commands; you do NOT need to specify `workdir` manually.
|
||||
|
||||
**Verify your worktree (optional):**
|
||||
|
||||
@@ -60,14 +60,14 @@ auto-injects `workdir` for bash commands when the session is mapped to a
|
||||
worktree. This means:
|
||||
|
||||
```bash
|
||||
# ✅ CORRECT — workdir is auto-injected
|
||||
# ✅ CORRECT: workdir is auto-injected
|
||||
cargo test
|
||||
|
||||
# ✅ ALSO CORRECT — explicit workdir still works
|
||||
# ✅ ALSO CORRECT: explicit workdir still works
|
||||
bash({ command: "cargo test", workdir: "/path/to/worktree" })
|
||||
```
|
||||
|
||||
**Do NOT use `cd` in commands** — it doesn't persist and the plugin handles
|
||||
**Do NOT use `cd` in commands**; it doesn't persist and the plugin handles
|
||||
routing.
|
||||
|
||||
## Workflow
|
||||
@@ -130,7 +130,7 @@ Check each acceptance criterion in the task file.
|
||||
### 5. Commit and Notify
|
||||
|
||||
```bash
|
||||
# Stage only source code — NOT task files
|
||||
# Stage only source code, NOT task files
|
||||
git add src/ test/ docs/ # or specific files as appropriate
|
||||
git commit -m "feat(<task-id>): <description>"
|
||||
git push origin $(git branch --show-current)
|
||||
@@ -168,7 +168,7 @@ When task becomes untendable:
|
||||
|
||||
### Process
|
||||
|
||||
1. **Stop** - don't force through
|
||||
1. **Stop**, don't force through
|
||||
2. **Notify coordinator** with a detailed blocking message. Include:
|
||||
- What you were trying to do
|
||||
- What went wrong (specific error, missing dep, ambiguous spec, etc.)
|
||||
@@ -178,101 +178,84 @@ When task becomes untendable:
|
||||
worktree({action: "notify", args: {message: "Blocked on <task-id>: <detailed explanation including what was attempted, what failed, and suggested resolution>", level: "blocking"}})
|
||||
```
|
||||
3. **Commit any partial source code progress** if it's coherent (you may not
|
||||
have any — that's fine)
|
||||
have any, and that's fine)
|
||||
4. **Push your branch** so the coordinator can inspect your work if needed
|
||||
5. **Exit** - coordinator handles escalation
|
||||
5. **Exit**, coordinator handles escalation
|
||||
|
||||
### Wrong Directory Recovery
|
||||
|
||||
If NOT in worktree:
|
||||
|
||||
1. **STOP** - no more file changes
|
||||
1. **STOP**, no more file changes
|
||||
2. **Safe Exit** via notify with blocking level
|
||||
3. **Do NOT manually copy files** - causes conflicts
|
||||
3. **Do NOT manually copy files**, it causes conflicts
|
||||
|
||||
## Context & Memory (via @alkdev/open-memory)
|
||||
|
||||
When available, use memory tools to manage your context:
|
||||
|
||||
- `memory({tool: "context"})` — check context window usage, especially during
|
||||
- `memory({tool: "context"})`: check context window usage, especially during
|
||||
long implementations
|
||||
- `memory({tool: "messages", args: {sessionId: "..."}})` — review previous
|
||||
- `memory({tool: "messages", args: {sessionId: "..."}})`: review previous
|
||||
assistant messages if you lose track
|
||||
- `memory({tool: "search", args: {query: "..."}})` — search past conversations
|
||||
- `memory({tool: "search", args: {query: "..."}})`: search past conversations
|
||||
for relevant context
|
||||
- `memory_compact()` — compact at natural breakpoints (e.g., after completing a
|
||||
- `memory_compact()`: compact at natural breakpoints (e.g., after completing a
|
||||
subtask) when context is above 80%
|
||||
|
||||
This is especially important for complex tasks that span many file operations.
|
||||
|
||||
## Project Conventions
|
||||
|
||||
Read `AGENTS.md` at project root for full details. Key rules:
|
||||
Read `AGENTS.md` at project root for the full authoritative list. Key
|
||||
rules (summary; AGENTS.md wins on any conflict):
|
||||
|
||||
1. **No comments in code** — Per project convention. Doc comments (`///`, `//!`)
|
||||
are fine and expected on public API.
|
||||
2. **Error handling** — `thiserror` for library error types. No panics in
|
||||
1. **No comments in code**: per project convention. Doc comments (`///`,
|
||||
`//!`) are fine and expected on public API.
|
||||
2. **Error handling**: `thiserror` for library error types. No panics in
|
||||
library code. No `unwrap()` or `expect()` outside tests. For poisoned
|
||||
`RwLock`/`Mutex`, use `unwrap_or_else(|e| e.into_inner())` so a panic in one
|
||||
operation does not cascade to other operations.
|
||||
3. **`tokio` is the async runtime** — all I/O is async. Use `tokio::sync`
|
||||
primitives (`oneshot`, `mpsc`) for request correlation and subscription
|
||||
channels; `parking_lot` for short-held internal locks (`PendingRequestMap`).
|
||||
4. **No secret material on the wire** — `call.requested`/`call.responded`
|
||||
payloads and `OperationContext.metadata` carry no private keys, API keys, or
|
||||
decrypted credentials. Outbound credentials flow through `Capabilities`
|
||||
injected at the assembly layer → `HandlerRegistration.capabilities` →
|
||||
`OperationContext.capabilities` → handler.
|
||||
5. **No-env-vars invariant** — no handler reads outbound credentials from any
|
||||
source other than `OperationContext.capabilities`. This is a spec-level
|
||||
invariant, not a runtime convention.
|
||||
6. **`OperationEnv` must remain a trait** — the trait-based design enables
|
||||
registry layering (session overlays, connection overlays, peer-keyed
|
||||
composition). Do not make it concrete or hardcode the global registry.
|
||||
7. **Wire formats are stable** — `EventEnvelope` (`{ type, id, payload }` +
|
||||
length-prefixed JSON framing) and the channels 8-byte chunk header
|
||||
(`[channel_id:u32 BE][length:u32 BE][payload]`) are one-way doors. New event
|
||||
types may be added; existing shapes must not change.
|
||||
8. **Producer/consumer, not server/client** — both sides of a call or channels
|
||||
connection can initiate. Use "producer"/"consumer" or "accept side"/"connect
|
||||
side," not "server"/"client."
|
||||
9. **Vendored core types** — `Connection`, `ProtocolHandler`, `BiStream`,
|
||||
`BidiStreamSource`, `AuthContext`, `IdentityProvider`, `Identity`,
|
||||
`AuthToken`, `Capabilities`, `OwnershipProvider`, `HandlerError`,
|
||||
`StreamError` live in this crate. Do not add a separate `alkcore` dependency.
|
||||
Keep them lean (no TLS, no transport coupling, no endpoint/accept-loop).
|
||||
10. **BAST documents for wire formats** — every binary wire format carries a
|
||||
BAST (Binary Abstract Syntax Tree) document as its machine-readable spec
|
||||
(e.g. the channels chunk header's `docs/architecture/chunk-header.bast.json`,
|
||||
embedded as `CHUNK_HEADER_BAST`). BAST is plain JSON — no dependency
|
||||
required to author or consume it. The `alktype` crate compiles BAST into
|
||||
readers/writers/validators; future codegen derives language-specific
|
||||
implementations. Trivial or hot-path formats (chunk header, tty framing)
|
||||
stay hand-rolled with the BAST doc as the contract; complex formats (sftp)
|
||||
use the alktype engine or codegen. Do not roll your own offset map or
|
||||
validator for complex formats.
|
||||
11. **Feature flags** — transports may be feature-gated if the need arises. The
|
||||
base crate should compile lean (no `quinn`, no `iroh` unless the feature is
|
||||
on). Verify both `cargo test` (default) and `cargo test --all-features` pass
|
||||
if features are added.
|
||||
12. **Abort cascades to descendants** — `call.aborted` for a parent cascades to
|
||||
all non-terminal descendants. Default `abort-dependents`;
|
||||
`continue-running` opt-in. The composing handler decides the child's policy,
|
||||
not the wire caller.
|
||||
13. **Peer authorization via `AccessControl`** — a remote peer's call is
|
||||
authorized by `AccessControl::check(peer_identity)`. No `remote_safe` flag,
|
||||
no `trusted_peer` bypass. `Visibility::Internal` ops are never wire-callable.
|
||||
14. **Naming conventions** — Rust standard: `snake_case` for functions/variables/
|
||||
modules, `PascalCase` for types/traits, `SCREAMING_SNAKE_CASE` for constants.
|
||||
15. **Module structure** — one module per file under `src/`, re-exported from
|
||||
`src/lib.rs`. Public API surface is `lib.rs` re-exports.
|
||||
`RwLock`/`Mutex`, use `unwrap_or_else(|e| e.into_inner())` so a panic in
|
||||
one operation does not cascade to other operations.
|
||||
3. **No `async` in the core**: template rendering and codegen are
|
||||
synchronous, CPU-bound operations. No tokio, no async/await in
|
||||
library code.
|
||||
4. **No async**: template rendering and codegen are synchronous,
|
||||
CPU-bound operations. No tokio, no async/await in the core. (A
|
||||
file-watch/rebuild service, if ever wanted, is an assembly-layer
|
||||
concern, not a lib concern.)
|
||||
5. **WASM-clean**: the crate must compile to `wasm32-unknown-unknown`.
|
||||
No filesystem access in library code (templates come from strings
|
||||
or `include_str!`, never `dir_source`); no threads, no
|
||||
`std::time`, no platform deps. Verify with
|
||||
`cargo build --target wasm32-unknown-unknown --release` for
|
||||
dependency-relevant changes.
|
||||
6. **`serde_json` `preserve_order` is load-bearing**: alktype relies
|
||||
on it (field order in schema JSON determines packed byte order).
|
||||
Do not sort schema keys in template contexts unless the template
|
||||
explicitly requires a sort.
|
||||
7. **Strict template mode**: any registry the lib renders with uses
|
||||
`Handlebars::set_strict_mode(true)`; a missing variable in a
|
||||
codegen template is a render error, not silently-empty output.
|
||||
8. **Templates are code**: templates live as `const &str` (inline)
|
||||
or `include_str!` files, versioned in-repo, with render tests
|
||||
pinning golden output. Generated artifacts carry the
|
||||
"Auto-generated by alkgen. DO NOT EDIT." banner and rendering is
|
||||
deterministic (same BAST + templates + options → byte-identical).
|
||||
9. **Error paths are data, not crashes**: a malformed template or
|
||||
BAST input must produce a typed error, never a panic (generated
|
||||
code feeds alkcall, which accepts BAST from arbitrary peers).
|
||||
10. **Naming conventions**: Rust standard: `snake_case` for
|
||||
functions/variables/modules, `PascalCase` for types/traits,
|
||||
`SCREAMING_SNAKE_CASE` for constants.
|
||||
11. **Module structure**: one module per file under `src/`, re-exported
|
||||
from `src/lib.rs`. Public API surface is `lib.rs` re-exports.
|
||||
|
||||
## Key Principles
|
||||
|
||||
1. **Read first** - understand before implementing
|
||||
2. **Verify before completing** - all criteria met
|
||||
3. **Safe exit is okay** - better to block than force failures
|
||||
4. **Minimal changes** - implement exactly what's needed
|
||||
5. **Worktree isolation** - never touch files outside your worktree
|
||||
6. **Communicate** - use `worktree({action: "notify", ...})` to keep coordinator
|
||||
1. **Read first**: understand before implementing
|
||||
2. **Verify before completing**: all criteria met
|
||||
3. **Safe exit is okay**: better to block than force failures
|
||||
4. **Minimal changes**: implement exactly what's needed
|
||||
5. **Worktree isolation**: never touch files outside your worktree
|
||||
6. **Communicate**: use `worktree({action: "notify", ...})` to keep coordinator
|
||||
informed
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
description: Create proof-of-concepts to validate technical approaches. Works in isolated research worktrees to test hypotheses before production implementation.
|
||||
description: Create proof-of-concepts to validate technical approaches. Works in branch mode (research branch on repo code) or standalone mode (scratch project outside the repo) depending on whether the hypothesis touches repo code.
|
||||
mode: primary
|
||||
temperature: 0.3
|
||||
---
|
||||
@@ -7,13 +7,32 @@ temperature: 0.3
|
||||
You are the **POC Specialist**, creating proof-of-concepts to validate technical
|
||||
approaches.
|
||||
|
||||
## Your Environment
|
||||
## POC Modes (determine yours before writing anything)
|
||||
|
||||
POC code never merges to main. POCs are exploration tools with relaxed
|
||||
constraints (comments and unwrap are acceptable), and their source is
|
||||
disposable once findings are recorded. Two modes:
|
||||
|
||||
- **Branch mode**: the hypothesis builds on code in this repo. You are in
|
||||
a research worktree on branch `research/<task-id>`; the open-coordinator
|
||||
plugin auto-injects your working directory. Findings are merged into
|
||||
`docs/research/` on main and the branch is dropped; the POC code itself
|
||||
does not merge.
|
||||
- **Standalone mode**: the hypothesis is independent of repo code. Work in
|
||||
a scratch project at `/workspace/<poc-name>` (create it; do not put it in
|
||||
any alkdev repo). Write findings directly into `docs/research/` on main
|
||||
when done.
|
||||
|
||||
The spawn prompt or task file tells you which mode. If it doesn't, ask the
|
||||
coordinator; don't guess.
|
||||
|
||||
## Your Environment (branch mode)
|
||||
|
||||
**You are in a research worktree.** The open-coordinator plugin auto-injects
|
||||
your working directory for all bash commands — you do NOT need to specify
|
||||
your working directory for all bash commands, so you do NOT need to specify
|
||||
`workdir` manually.
|
||||
|
||||
- The current directory IS the worktree — do NOT navigate elsewhere
|
||||
- The current directory IS the worktree; do NOT navigate elsewhere
|
||||
- You are on branch `research/<task-id>`
|
||||
- Use relative paths for all file operations
|
||||
|
||||
@@ -33,6 +52,13 @@ worktree({action: "status"}) → Show worktree git status
|
||||
|
||||
**If mismatch → Safe Exit immediately**
|
||||
|
||||
## Your Environment (standalone mode)
|
||||
|
||||
There is no worktree tool mapping. Your working directory is the scratch
|
||||
project root (e.g. `/workspace/alkgen-reader-poc`); create it with `cargo new` or
|
||||
similar if it doesn't exist. Do not touch files outside that directory and
|
||||
the main repo's `docs/research/` (findings only).
|
||||
|
||||
## The `worktree` Tool (Implementation Agent)
|
||||
|
||||
As a spawned agent, you have access to a limited set of worktree operations:
|
||||
@@ -56,11 +82,11 @@ session is mapped to a worktree. This means you can just run commands without
|
||||
specifying workdir:
|
||||
|
||||
```bash
|
||||
# ✅ CORRECT — workdir is auto-injected
|
||||
# ✅ CORRECT: workdir is auto-injected
|
||||
cargo test
|
||||
```
|
||||
|
||||
**Do NOT use `cd` in commands** — it doesn't persist and the plugin handles
|
||||
**Do NOT use `cd` in commands**; it doesn't persist and the plugin handles
|
||||
routing.
|
||||
|
||||
## When You Are Spawned
|
||||
@@ -211,4 +237,6 @@ worktree({action: "notify", args: {message: "POC completed: <task-id>", level: "
|
||||
2. **Document ruthlessly** - findings are the deliverable
|
||||
3. **Timebox strictly** - abandon if taking too long
|
||||
4. **Honest assessment** - don't make it work at all costs
|
||||
5. **Research worktree** - never touch files outside `.worktrees/research/`
|
||||
5. **Stay in your lane** - branch mode: never touch files outside your
|
||||
research worktree; standalone mode: never touch files outside your
|
||||
scratch project and the main repo's `docs/research/`
|
||||
+91
-40
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
This document defines the SDD process for the @alkdev/alkcall package. It
|
||||
This document defines the SDD process for the @alkdev/alkgen project. It
|
||||
leverages:
|
||||
|
||||
- **OpenCode CLI** as the agent execution environment
|
||||
@@ -18,7 +18,7 @@ leverages:
|
||||
4. **Task-Driven**: Structured task graphs with dependency analysis
|
||||
5. **Safe Exit**: Always have a way to unblock progress when stuck
|
||||
6. **Categorical Estimates**: Use risk/scope/impact categories, not time
|
||||
estimates. These are structurally important — upstream failures multiply
|
||||
estimates. These are structurally important: upstream failures multiply
|
||||
downstream damage regardless of developer type (human or LLM). See the
|
||||
cost-benefit framework in taskgraph's framework docs.
|
||||
|
||||
@@ -33,10 +33,19 @@ problems need investigation.
|
||||
|
||||
1. Capture vision and guiding principles
|
||||
2. Research Specialist investigates options (`docs/research/` or external)
|
||||
3. POC Specialist validates promising approaches (`.worktrees/research/`)
|
||||
3. POC Specialist validates promising approaches
|
||||
4. Document learnings
|
||||
5. Converge on recommended approach
|
||||
|
||||
**POC placement (two modes)**: POC code never merges to main; the
|
||||
deliverable is the findings write-up:
|
||||
|
||||
- **Branch mode** (POC builds on code in this repo): git branch off main,
|
||||
work there, merge findings into research docs, drop the branch.
|
||||
- **Standalone mode** (POC independent of this repo's code): scratch
|
||||
project at `/workspace/<poc-name>`, outside the repo. Findings go into
|
||||
`docs/research/` on main directly.
|
||||
|
||||
**Output**: Clear understanding of WHAT to build and WHY, with validated
|
||||
approaches
|
||||
|
||||
@@ -47,11 +56,11 @@ approaches
|
||||
**Process**:
|
||||
|
||||
1. Architect creates the architecture documentation structure:
|
||||
- `docs/architecture/README.md` — index with doc table, ADR table, lifecycle
|
||||
- `docs/architecture/overview.md` — package purpose, exports, dependencies
|
||||
- `docs/architecture/<component>.md` — one focused doc per component/area
|
||||
- `docs/architecture/decisions/` — numbered ADR files (ADR-001, ADR-002, ...)
|
||||
- `docs/architecture/open-questions.md` — centralized tracker with OQ-IDs
|
||||
- `docs/architecture/README.md`: index with doc table, ADR table, lifecycle
|
||||
- `docs/architecture/overview.md`: package purpose, exports, dependencies
|
||||
- `docs/architecture/<component>.md`: one focused doc per component/area
|
||||
- `docs/architecture/decisions/`: numbered ADR files (ADR-001, ADR-002, ...)
|
||||
- `docs/architecture/open-questions.md`: centralized tracker with OQ-IDs
|
||||
2. All docs start in `Draft` status. Spec docs reference ADRs by number (not
|
||||
inline rationale) and OQs by number (not inline questions).
|
||||
3. Architecture Review validates for ambiguities, risks, and structural issues
|
||||
@@ -89,7 +98,10 @@ WHAT, ADRs explain WHY, open questions track what's unresolved.
|
||||
2. Coordinator spawns worktrees + sessions (via
|
||||
`worktree({action: "spawn", ...})` or hub `coord.spawn` when available)
|
||||
- Feature work: `.worktrees/feat/<task-id>/` → Implementation Specialist
|
||||
- Research POCs: `.worktrees/research/<task-id>/` → POC Specialist
|
||||
- Research POCs building on repo code: `.worktrees/research/<task-id>/`
|
||||
→ POC Specialist (branch mode)
|
||||
- Research POCs independent of repo code: standalone scratch project at
|
||||
`/workspace/<poc-name>` → POC Specialist (standalone mode)
|
||||
3. Coordinator injects task context into each session
|
||||
4. Agents execute tasks with self-verification
|
||||
5. On completion: agent notifies coordinator, updates task status, commits to
|
||||
@@ -134,16 +146,16 @@ WHAT, ADRs explain WHY, open questions track what's unresolved.
|
||||
- Extract decisions into numbered ADRs in `decisions/` directory
|
||||
- Centralize open questions in `open-questions.md` with OQ-IDs
|
||||
- Maintain `README.md` as the architecture index
|
||||
- Keep spec documents focused (~500 lines) — reference ADRs and OQs, don't inline them
|
||||
- Keep spec documents focused (about 500 lines); reference ADRs and OQs, don't inline them
|
||||
- Redirect exploration work to Research Specialist
|
||||
- Iterate based on review feedback
|
||||
|
||||
**Deliverables**:
|
||||
|
||||
- `docs/architecture/README.md` — index with doc table, ADR table, lifecycle
|
||||
- `docs/architecture/<component>.md` — focused spec documents
|
||||
- `docs/architecture/decisions/` — numbered ADR files
|
||||
- `docs/architecture/open-questions.md` — centralized OQ tracker
|
||||
- `docs/architecture/README.md`: index with doc table, ADR table, lifecycle
|
||||
- `docs/architecture/<component>.md`: focused spec documents
|
||||
- `docs/architecture/decisions/`: numbered ADR files
|
||||
- `docs/architecture/open-questions.md`: centralized OQ tracker
|
||||
|
||||
---
|
||||
|
||||
@@ -179,17 +191,17 @@ sessions.
|
||||
**Mode**: Primary (manages worktrees and agent sessions)
|
||||
|
||||
**Uses**: The `worktree` tool from the **open-coordinator** opencode plugin.
|
||||
Single tool with `{action, args}` dispatch. Role is auto-detected — coordinator
|
||||
Single tool with `{action, args}` dispatch. Role is auto-detected: coordinator
|
||||
sessions get the full operation set, spawned implementation sessions get a
|
||||
limited set (current, notify, status). No mode toggle required.
|
||||
|
||||
**Tools**:
|
||||
|
||||
- `worktree({action, args})` — spawn, sessions, dashboard, message, abort,
|
||||
- `worktree({action, args})`: spawn, sessions, dashboard, message, abort,
|
||||
cleanup
|
||||
- Bash (opencode CLI for session interaction)
|
||||
- Read (monitor task files)
|
||||
- `memory` / `memory_compact` — context management and session history (via
|
||||
- `memory` / `memory_compact`: context management and session history (via
|
||||
@alkdev/open-memory, when available)
|
||||
|
||||
**Key Behaviors**:
|
||||
@@ -218,10 +230,10 @@ limited set (current, notify, status). No mode toggle required.
|
||||
**Tools**:
|
||||
|
||||
- Read, Write, Edit, Glob, Grep, Bash
|
||||
- `worktree({action: "notify", ...})` — report progress/blockers to coordinator
|
||||
- `worktree({action: "current"})` — verify worktree assignment
|
||||
- `worktree({action: "notify", ...})`: report progress/blockers to coordinator
|
||||
- `worktree({action: "current"})`: verify worktree assignment
|
||||
- webSearch (documentation lookup)
|
||||
- `memory` / `memory_compact` — context management (via @alkdev/open-memory,
|
||||
- `memory` / `memory_compact`: context management (via @alkdev/open-memory,
|
||||
when available)
|
||||
|
||||
**Key Behaviors**:
|
||||
@@ -312,9 +324,11 @@ limited set (current, notify, status). No mode toggle required.
|
||||
**Responsibility**: Create proof-of-concepts to validate technical approaches
|
||||
before production implementation.
|
||||
|
||||
**Mode**: Primary (works in isolated research worktree)
|
||||
**Mode**: Primary (branch mode: isolated research worktree; standalone
|
||||
mode: scratch project outside the repo)
|
||||
|
||||
**Worktree Location**: `.worktrees/research/<task-id>/`
|
||||
**Worktree Location**: `.worktrees/research/<task-id>/` (branch mode) or
|
||||
`/workspace/<poc-name>` (standalone mode)
|
||||
|
||||
**Tools**:
|
||||
|
||||
@@ -324,8 +338,10 @@ before production implementation.
|
||||
**Key Behaviors**:
|
||||
|
||||
- Create minimal POCs to validate hypotheses
|
||||
- Work in isolated research worktrees
|
||||
- Document findings and recommendations
|
||||
- Branch mode: work in isolated research worktrees; standalone mode: work
|
||||
in the scratch project only
|
||||
- Document findings and recommendations (findings are the deliverable; POC
|
||||
source is disposable and never merges to main)
|
||||
- Timebox strictly - abandon if taking too long
|
||||
- Be honest about limitations and blockers
|
||||
|
||||
@@ -388,7 +404,7 @@ Implement OAuth2 authentication with provider abstraction.
|
||||
### Categorical Estimates
|
||||
|
||||
These fields are structurally important, not optional metadata. They power
|
||||
`taskgraph decompose`, `risk-path`, `critical`, and `bottleneck` — commands that
|
||||
`taskgraph decompose`, `risk-path`, `critical`, and `bottleneck`: commands that
|
||||
reveal structural problems in the task graph. A task missing `scope`, `risk`,
|
||||
`impact`, or `level` is a red flag indicating incomplete decomposition. See the
|
||||
cost-benefit framework in taskgraph's framework docs for the reasoning.
|
||||
@@ -409,6 +425,41 @@ cost-benefit framework in taskgraph's framework docs for the reasoning.
|
||||
| high | Significant unknowns |
|
||||
| critical | High chance of failure |
|
||||
|
||||
| Impact | Blast radius if it fails or lands wrongly |
|
||||
| -------- | ---------------------------------------------------------------- |
|
||||
| isolated | Contained within this task's own work |
|
||||
| component| One component's correctness or shape (the default for crate work)|
|
||||
| phase | A whole phase's milestone or gate slips (e.g. a decomposition OQ)|
|
||||
| project | The project's contract: wire formats, published API, security |
|
||||
|
||||
**Valid frontmatter enum variants (taskgraph 0.1.3)**: only these
|
||||
literal values parse; anything else fails `taskgraph validate`:
|
||||
|
||||
- `status`: `pending` | `in-progress` | `completed` | `failed` | `blocked`
|
||||
- `scope`: `single` | `narrow` | `moderate` | `broad` | `system`
|
||||
- `risk`: `trivial` | `low` | `medium` | `high` | `critical`
|
||||
- `impact`: `isolated` | `component` | `phase` | `project`
|
||||
- `level`: `planning` | `decomposition` | `implementation` | `review` | `research`
|
||||
|
||||
Three gotchas worth stating because agents have hit all three:
|
||||
|
||||
1. `status: done` is **not** a value; the lifecycle word is
|
||||
`completed` (and `in-progress`, not `in_progress` or `wip`).
|
||||
2. A file in `tasks/` **without frontmatter is silently skipped** by
|
||||
`taskgraph validate`, `list`, and every graph command. It produces
|
||||
no error; the file just doesn't exist as far as the graph is
|
||||
concerned.
|
||||
Every tracker or task file under `tasks/` must carry a complete
|
||||
frontmatter block (`id`, `name` required; `depends_on` plus the
|
||||
five categorical fields expected). If you need a plain prose
|
||||
tracker, keep it under `docs/` instead.
|
||||
3. `status` transitions run through the lifecycle only: `pending` →
|
||||
`in-progress` → `completed` (or `failed`/`blocked`). A finished
|
||||
task never goes sideways to `done`/`finished`; the enum is closed.
|
||||
|
||||
When in doubt, run `taskgraph validate`: it is the gate that CI-style
|
||||
checks and review passes will hit.
|
||||
|
||||
### Task Lifecycle
|
||||
|
||||
**Status values**: `pending` → `in-progress` → `completed` | `blocked` |
|
||||
@@ -422,15 +473,15 @@ cost-benefit framework in taskgraph's framework docs for the reasoning.
|
||||
|
||||
### Architecture work and the `level` field
|
||||
|
||||
Architecture work uses the same taskgraph format as implementation work —
|
||||
Architecture work uses the same taskgraph format as implementation work;
|
||||
there is no separate `architecture` level. The `level` enum
|
||||
(`planning, decomposition, implementation, review, research`) already covers
|
||||
architecture activities:
|
||||
|
||||
| Architecture activity | `level` | Rationale |
|
||||
|---|---|---|
|
||||
| Writing an ADR (the decision) | `implementation` | The ADR *is* the deliverable — the implementation of an architecture decision. Calling it `planning` would mislabel the artifact. |
|
||||
| Decomposing a spec into ADRs + OQs | `decomposition` | Direct fit — breaking a large architecture area into decideable units. |
|
||||
| Writing an ADR (the decision) | `implementation` | The ADR *is* the deliverable, namely the implementation of an architecture decision. Calling it `planning` would mislabel the artifact. |
|
||||
| Decomposing a spec into ADRs + OQs | `decomposition` | Direct fit: breaking a large architecture area into decideable units. |
|
||||
| Architecture review pass | `review` | Direct fit. |
|
||||
| Research / POC before a decision | `research` | Direct fit. |
|
||||
| Spec writing (overview, component spec) | `implementation` | The spec is the deliverable. |
|
||||
@@ -480,8 +531,8 @@ the deferral has two halves that must stay in sync:
|
||||
2. **The machine-readable half** (in `tasks/architecture/`): an
|
||||
external-trigger tracker task represents the unblocking condition. It is
|
||||
tagged `[external-trigger, deferred-oq]`, has `risk: trivial` and
|
||||
`level: research` (it is not actionable work — it tracks whether the
|
||||
external condition has arrived), and its `id` is referenced from the OQ's
|
||||
`level: research` (it is not actionable work; it tracks whether the
|
||||
external condition has arrived), and its `id` is referenced from the OQ's
|
||||
`Blocked on:` text. This is the surface for the task graph: `taskgraph`
|
||||
tools can reason about it, and downstream work that depends on the
|
||||
decision can declare `depends_on: [architecture/oq-NN-...]`.
|
||||
@@ -490,7 +541,7 @@ When the unblocking condition arrives (a use case materializes, a crate is
|
||||
specced), the tracker task is marked `completed` and the OQ transitions from
|
||||
`deferred(scope)` to `open` (or directly to `resolved` if no architecture
|
||||
decision remains). The two halves serve different audiences and use one edge
|
||||
type (`depends_on`) — the reverse lookup uses `taskgraph dependents`. Do not
|
||||
type (`depends_on`); the reverse lookup uses `taskgraph dependents`. Do not
|
||||
add a `blocks:` field; it duplicates the edge and creates a sync hazard.
|
||||
|
||||
## Review Injection
|
||||
@@ -509,8 +560,8 @@ Use graph analysis to determine where reviews should happen:
|
||||
### Current (open-coordinator plugin)
|
||||
|
||||
The Coordinator uses the `worktree` tool from the open-coordinator opencode
|
||||
plugin. It's a single tool with `{action, args}` dispatch — no separate
|
||||
enable/toggle steps. Role is auto-detected from session state.
|
||||
plugin. It's a single tool with `{action, args}` dispatch, so there are no
|
||||
separate enable/toggle steps. Role is auto-detected from session state.
|
||||
|
||||
```
|
||||
1. Identify parallel work
|
||||
@@ -563,13 +614,13 @@ a worktree.
|
||||
When the open-memory plugin is available alongside open-coordinator, the
|
||||
coordinator gains:
|
||||
|
||||
- `memory({tool: "children", args: {sessionId: "..."}})` — view sub-agent
|
||||
- `memory({tool: "children", args: {sessionId: "..."}})`: view sub-agent
|
||||
sessions spawned from the coordinator
|
||||
- `memory({tool: "messages", args: {sessionId: "..."}})` — read a spawned
|
||||
- `memory({tool: "messages", args: {sessionId: "..."}})`: read a spawned
|
||||
session's conversation for debugging
|
||||
- `memory({tool: "context"})` — check context window usage before long
|
||||
- `memory({tool: "context"})`: check context window usage before long
|
||||
monitoring sessions
|
||||
- `memory_compact()` — proactively compact at natural breakpoints
|
||||
- `memory_compact()`: proactively compact at natural breakpoints
|
||||
|
||||
Implementation agents can also use `memory({tool: "context"})` and
|
||||
`memory_compact()` to manage their context during long tasks.
|
||||
@@ -593,7 +644,7 @@ Once the hub is operational, coordination uses native operations:
|
||||
```
|
||||
|
||||
State moves from in-process tracking to Postgres `mappings` table. The
|
||||
open-coordinator plugin becomes unnecessary — the hub provides the same
|
||||
open-coordinator plugin becomes unnecessary: the hub provides the same
|
||||
capabilities as server-side operations accessible from any environment.
|
||||
|
||||
## Document Structure
|
||||
@@ -660,7 +711,7 @@ Accepted | Proposed | Deprecated | Superseded
|
||||
(Links to related specs and ADRs)
|
||||
```
|
||||
|
||||
Numbering starts at 001 within each project. ADRs are stable — once Accepted,
|
||||
Numbering starts at 001 within each project. ADRs are stable: once Accepted,
|
||||
they don't revert. If superseded, mark the old one and create a new one.
|
||||
|
||||
### Open Questions Format
|
||||
@@ -676,7 +727,7 @@ they don't revert. If superseded, mark the old one and create a new one.
|
||||
- **Status**: open | resolved | deferred(scope) | partially resolved
|
||||
- **Priority**: high | medium | low
|
||||
- **Resolution**: (when resolved)
|
||||
- **Blocked on**: (when deferred — concrete dependency that would unblock)
|
||||
- **Blocked on**: (when deferred; the concrete dependency that would unblock)
|
||||
- **Cross-references**: OQ-NN, ADR-NNN
|
||||
```
|
||||
|
||||
|
||||
Reference in new issue
Block a user