# Design Decisions

Why this repository is laid out the way it is. If you're about to refactor
something to "modernize" or "simplify" it, read the relevant section first — most
of these choices have a reason that isn't obvious from the files, and reversing
them breaks either discovery, the ship boundary, or the methodology itself.

This document is for AI agents and human contributors who need the *why*, not
just the *what*. The conventions themselves are in [`AGENTS.md`](../AGENTS.md).
The behavior is in [`skills/deepworkplan/SKILL.md`](../skills/deepworkplan/SKILL.md)
and the normative standard under
[`skills/deepworkplan/spec/`](../skills/deepworkplan/spec/README.md).

---

## 1. Router meta-skill + sub-skills (not one big SKILL.md)

We ship **one discoverable skill** (`deepworkplan`) that routes to six internal
sub-skills (`onboard`, `create`, `execute`, `refine`, `resume`, `status`). An
alternative would have been a single multi-thousand-line `SKILL.md` covering
everything.

We chose the router approach because:

- **Description-based discovery works better with focused descriptions.** When an
  agent decides "should I activate this skill?", it reads the `description`
  field. A focused description like *"Resume an interrupted plan from its
  recorded progress"* triggers more accurately than a generic *"Do anything with
  plans"*.
- **Different invocation policies per capability.** Each sub-skill is its own
  `/deepworkplan-*` slash command with its own frontmatter, so users can invoke
  exactly the verb they want.
- **Independent symlinks via `setup.sh`.** Users get
  `~/.claude/skills/deepworkplan-create` etc. as standalone commands. This
  requires each sub-skill to live in its own folder.
- **Easier to evolve one capability without touching others.** A change to
  `execute/SKILL.md` doesn't ripple into `onboard/`.

Trade-off: more files. We accept that — for a public skill people will audit,
focused files beat one giant one.

## 2. Everything under `skills/deepworkplan/` (not `SKILL.md` at repo root)

skills.sh discovers skills in two patterns: a `SKILL.md` at the repo root (for
single-skill repos), or `skills/<name>/SKILL.md` (for single or multi-skill
packs). We use the second pattern even though we ship one logical skill because:

- It lets us keep dev infrastructure at the repo root (`AGENTS.md`, `tests/`,
  `scripts/`, `docs/`, `.github/`) without ambiguity. With the root pattern,
  every root file becomes part of the "skill" semantically.
- The boundary "what ships at runtime" is unambiguous: **anything inside
  `skills/deepworkplan/` ships, anything outside doesn't.** No `.skillignore`-style
  exclusion list to maintain.

The CI ship-boundary discipline (and `AGENTS.md` rule #2) depend on this holding.

## 3. `shared/`, `spec/`, `guide/`, `examples/`, `addons/` live **inside** the pack

`context.sh`, `dwp-paths.md`, `adaptation.md`, the RFC-2119 spec, the methodology
guide, the templates, and the addons are all under `skills/deepworkplan/` even
though they're "reference material," because:

- skills.sh and `setup.sh` install the **pack directory**. If `spec/` or
  `shared/` were siblings (e.g. `skills/_shared/`), an installed
  `deepworkplan/SKILL.md` referencing `../shared/context.sh` wouldn't resolve on
  the user's machine.
- Every install must be self-contained. A sub-skill may read `../shared/`,
  `../spec/`, or `../examples/`, but it must never reach *out of*
  `skills/deepworkplan/`.

## 4. `setup.sh` exists alongside `npx skills add`

There are two install paths: `npx skills add DailybotHQ/deepworkplan-skill`
(skills.sh CLI, the canonical cross-agent installer) and `git clone && ./setup.sh`
(symlinks the pack and each sub-skill). `setup.sh` is not redundant:

- It works without Node.js / npm. Users in minimal containers, or who prefer not
  to add an npm dependency, get a pure-bash path.
- It makes the layout obvious — the script is small and readable and shows
  exactly which path the skill installs to per agent.
- It's the path you use while hacking on the skill locally: clone, edit, re-run
  setup, and your symlinked install picks up edits live.

## 5. `documentation_url` (not `homepage`) in frontmatter

Older Agent Skill examples used `homepage:` for the project URL. We use
`documentation_url:` because some agent harnesses interpret `homepage` as "fetch
this URL to refresh the skill content" — a remote-load semantics we explicitly
don't want. A single DNS/CDN issue could otherwise push modified instructions to
every installed user. `documentation_url` is unambiguous: a *reference link*, not
a *re-fetch source*. `scripts/validate-frontmatter.py` rejects any new
`homepage:` entries.

## 6. Kebab-case `name:` in frontmatter (not snake_case)

skills.sh URLs and flags use kebab-case (`deepworkplan-create`), and `setup.sh`
symlinks are kebab (`~/.claude/skills/deepworkplan-create`). Snake_case in
frontmatter plus kebab in symlinks is an inconsistency that confuses users and
breaks discovery for some agents. The validator rejects `deepworkplan_*` names.

## 7. The `.dwp/` output convention (gitignored working state)

All Deep Work Plan output lives in a gitignored `.dwp/` directory at the repo
root (`.dwp/plans/PLAN_<id>_<slug>/` for new plans; old unnumbered names are
preserved), resolved by
[`shared/context.sh`](../skills/deepworkplan/shared/context.sh) and overridable
via `DWP_DIR`. We chose a single conventional, gitignored directory because:

- **Plan artifacts are working state, not committed source.** They're how an
  agent and a developer coordinate a long-running effort — valuable during the
  work, noise in the git history afterward.
- **One predictable location** lets every sub-skill find prior plans without
  configuration, and lets onboarding add one line to `.gitignore` instead of
  scattering output across the tree.
- For orchestrator hubs, child plans nest under
  `repositories/<repo>/.dwp/plans/…` — same convention, applied per managed repo.

New plans receive a monotonic ID with a three-digit minimum (`001`, `002`,
`100`). The flat tree remains stable while a local `.next-plan-id` file
prevents reuse after deletion. Selection by ID and `latest` uses numeric order,
not filesystem modification time; unique slugs also resolve. Old unnumbered
plans are never renamed because their basename appears in state, contracts,
prompts, and evidence pointers. This is a forward-only naming policy, so no
plan migration runs on adoption.

This is a public contract (see `AGENTS.md` rule #5): changing the `.dwp/` layout
or the `DWP_DIR`/`DWP_AGENT_TOOL` env vars is a breaking change.

## 8. Reasoning over copy-paste (common baseline, reasoned remainder)

The skill is **markdown-first**: its "code" is instructions an agent reads and
then *reasons about*, not templates it blindly stamps out. As
[`shared/adaptation.md`](../skills/deepworkplan/shared/adaptation.md) puts it,
most of any generated artifact follows a fixed baseline shape, and the
remainder is reasoned from the target repo's actual stack, validation commands,
and module layout. The split is an observation from an audit of six
repositories, not a measured constant, and is not published as a ratio. We designed it this way because a skill that copy-pastes a fixed
`AGENTS.md` produces plausible-but-wrong docs for every repo that isn't the one
it was templated from. The onboarding presets under
[`onboard/presets/`](../skills/deepworkplan/onboard/presets/README.md) are
*reasoning starting points*, not files to copy verbatim.

## 9. Two archetypes (individual repo vs orchestrator hub)

Onboarding and plan execution branch on two repo archetypes, classified by a
heuristic in [`spec/ARCHETYPES.md`](../skills/deepworkplan/spec/ARCHETYPES.md): a
normal **individual repo** (the common case) and an **orchestrator hub** that
coordinates work across many managed repos. We encode this explicitly rather than
pretend one shape fits all because the orchestrator case needs child `.dwp/`
nesting, an `ORCHESTRATOR_MANIFEST.md`, and integration-checkpoint tasks that
would be dead weight in a single repo.

## 10. A normative RFC-2119 spec, shipped with the skill

The standard itself — five RFC-2119 documents under
[`spec/`](../skills/deepworkplan/spec/README.md) — ships inside the pack, not just
on the website. The skill *implements* a standard, and an agent benefits from
reading the MUST/SHOULD/MAY contract directly when it needs to resolve an
ambiguity. Keeping the spec versioned alongside the sub-skills also means the
standard and its implementation can never silently drift apart.

## 11. Addons are opt-in and non-blocking (one declared exception)

The `devcontainer` and `dailybot` addons under
[`addons/`](../skills/deepworkplan/addons/README.md) are opt-in, with one declared exception — the AI Diff Reviewer **local**
review is part of the 2.3.0 baseline (`spec/ADDONS.md` §6.5); its CI surface
stays opt-in. Core
DeepWorkPlan has **zero** dependency on either — the `dailybot` addon, for
instance, only wires optional progress reporting *if* the developer already has
Dailybot and consents, and it must never block plan execution. We keep addons
vendor-neutral and deferred so the core methodology stays useful to everyone and
the skill never becomes a covert install vector for a vendor's tooling.

## 12. Markdown-first: no network, no CLI, no auth, no consent prompts

Unlike skills that call a vendor API, DeepWorkPlan makes **no network calls,
ships no CLI, and needs no authentication**. The only executable code is two
bash helpers that read local git/filesystem state and emit JSON. This is a
deliberate security posture (see [`SECURITY.md`](../SECURITY.md)): the smaller
the runtime surface, the easier the skill is to audit and approve. It's also why
this repo has no consent/secret-scan flows — there's no outbound action to gate.

## 13. Versioning is automatic (conventional commits → auto-release)

`.github/workflows/auto-release.yml` reads the version from the router
`SKILL.md`, inspects conventional commits since the last tag, bumps every
`SKILL.md` in sync, prepends to `CHANGELOG.md`, tags, and creates a GitHub
Release on every merge to `main`. Contributors never hand-edit `version:` fields,
`CHANGELOG.md`, or tags. We automate this because a markdown skill spread across a
router plus nine sub-skills plus addons is exactly the kind of thing where
hand-bumping versions drifts out of sync — and a wrong version is what users see
first.

## 14. Lite first, Full by promotion (not a second planning product)

Every new request materializes one executable **Lite** plan directory. Lite keeps
the durable DWP contract — README, manifest, state, progress, prompts, analysis
results, task records, gates and Final Review — while storing bounded task records
inline instead of creating a large file per task. It is not a draft and it never
runs product work during creation.

The create skill recommends Lite or Full from scope, risk, dependencies and
expected horizon. `lite` and `full` are explicit overrides; `trust` changes only
whether a human reviews the recommendation. A Lite plan can be promoted safely
to Full before execution or between tasks, preserving task IDs and evidence. The
reverse conversion is deliberately absent: collapsing a detailed plan would make
state recovery and audit history ambiguous. This lets DWP structure a small
change without making long-horizon rigor optional.

## Vendored agent skills — three dogfood copies under `.agents/skills/`

This repo vendors **three** agent skills under `.agents/skills/`, all tracked
in git and pinned via [`skills-lock.json`](../skills-lock.json). They give any AI
agent that clones this repo the toolchain the DWP methodology recommends —
but they are managed differently on purpose:

| Vendored skill | Upstream | Release auto-refresh | Purpose in this repo |
|----------------|----------|----------------------|----------------------|
| `.agents/skills/deepworkplan/` | this repo (`skills/deepworkplan/`) | **No** | Contributor dogfood, kept **byte-identical** to `skills/deepworkplan/` (verified by checksum on every sync). It is excluded from release auto-refresh because that would pull the last published tag instead of this working revision. Sync with `bash scripts/refresh-dogfood-skill.sh`. |
| `.agents/skills/dailybot/` | [`DailybotHQ/agent-skill`](https://github.com/DailybotHQ/agent-skill) | **Yes** | Powers Dailybot standup reporting for plan lifecycle events (see the Dailybot addon) |
| `.agents/skills/ai-diff-reviewer/` | [`DailybotHQ/ai-diff-reviewer`](https://github.com/DailybotHQ/ai-diff-reviewer) | **Yes** | Powers the local code review (same `prompt.md` used by optional downstream CI integrations) |

**Why deepworkplan is excluded.** Blind `npx skills add --force` of this
repo's own skill into `.agents/skills/deepworkplan/` would overwrite the
dogfood copy. The release workflow still **smoke-tests** that
the published tag installs (into a temp directory); it does not commit that
install back into the tree. When the shipped pack under `skills/deepworkplan/`
changes and the dogfood copy should follow, run
`bash scripts/refresh-dogfood-skill.sh`, review, and commit.

**How addon refresh works.** [`.github/workflows/auto-release.yml`](../.github/workflows/auto-release.yml)
runs on every merge to `main` and, after cutting the release for this repo,
resolves the latest published tags of `agent-skill` and `ai-diff-reviewer`
(via `gh release view`), compares to the vendored `SKILL.md` `version:`, and
if either moved runs:

```bash
npx --yes skills add <repo>@<tag> --skill <name> --force -y
```

Both `--yes` (npm's proceed prompt) AND `-y` (the skills CLI's agent-picker
prompt) are required in a non-TTY runner — dropping either hangs the workflow
indefinitely. After each install the workflow asserts that the vendored
`SKILL.md`'s `version:` equals the requested tag; a mismatch fails the release.
If any file changes, the workflow commits
`chore(release): dogfood vendored <skill> to v<tag> [skip release]` and
pushes. The `[skip release]` marker prevents an infinite auto-release loop.

**Editing policy.**
- **Do not** hand-edit `.agents/skills/dailybot/` or `.agents/skills/ai-diff-reviewer/`
  — the next release will overwrite those. Contribute upstream, land a release
  there, then this repo's auto-release picks them up.
- **Do** treat `.agents/skills/deepworkplan/` as a generated mirror: refresh it only
  via `scripts/refresh-dogfood-skill.sh` (or an explicit reviewed edit), never
  via release dogfood.

**Pinned install commands are NOT auto-refreshed — and are CI-gated.**
Release dogfood updates the *vendored copy* under `.agents/skills/`. It does
**not** rewrite the install commands the shipped pack **teaches** under
`skills/deepworkplan/`, because those live in prose
(`npx --yes skills add DailybotHQ/ai-diff-reviewer@vX.Y.Z …`). The two drifted
apart once — the pack taught `@v2.0.0` while the vendored addon was already
`2.0.1`, so every repository onboarded from it installed a stale reviewer.

The invariant is now a CI gate: **every exact `ai-diff-reviewer@vX.Y.Z` pin in
`skills/deepworkplan/` must equal the `version:` of the vendored
`.agents/skills/ai-diff-reviewer/SKILL.md`** (`tests/agents-dogfood.bats`). When
a release moves the vendored addon, update the documented pins in the same PR —
`grep -rn 'ai-diff-reviewer@v[0-9]' skills/` finds them all.

`DailybotHQ/ai-diff-reviewer@v2` (no patch) is a different thing: the **GitHub
Action's floating major tag**, deliberately left floating so patch fixes flow
automatically. The gate ignores it. Do not pin it to a patch.
