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
14 changes: 13 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ jobs:
- name: Install test dependencies
run: python -m pip install pytest pyyaml
- name: Check shell syntax
run: bash -n init.sh scripts/dev_session.sh scripts/reconcile_sessions.sh scripts/lib/repo_root.sh scripts/hooks/pre-push
run: |
bash -n scripts/dev_session.sh scripts/reconcile_sessions.sh scripts/lib/repo_root.sh scripts/hooks/pre-push
sh -n init.sh
- name: init.sh must be executable
# The documented first command is `./init.sh`; a non-executable mode makes
# it fail for every adopter at step one.
run: test -x init.sh
- name: Run state and portability tests
run: python -m pytest scripts/lib/state_paths/tests scripts/tests -q
- name: Engines must work without PyYAML
# The stdlib config reader exists so engines carry no third-party
# dependency. Prove it in an env where PyYAML genuinely is not installed.
run: |
python -m pip uninstall -y pyyaml
python -m pytest scripts/tests/test_kitconfig.py -q
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ patterns to rules).

## Quickstart

**Prerequisites.** `init.sh` itself needs only POSIX `sh`, `awk`, and `git`. The
engines need [`uv`](https://docs.astral.sh/uv/) (they're PEP-723 single-file
scripts), `git`, and — for `pr-watch` / `parallel` — the GitHub CLI `gh`,
authenticated. No PyYAML: the config reader is stdlib-only.

```sh
# Click "Use this template" on GitHub and clone the result — or, into an
# existing repo, copy the kit's contents in from the root:
Expand All @@ -94,9 +99,34 @@ cp -r /path/to/agentic-dev-kit/. .
# -> start your agent session and invoke session-start
```

`init.sh` stamps your answers into `config/dev-model.yaml`, renders the narrative
docs from `docs/templates/`, installs the pre-push hook, and adds the state
sandbox to `.gitignore`. It never overwrites a narrative doc that is already in
use — only one still carrying the shipped `devkit-template: unrendered` marker.

Ten minutes, start to finish. For a full worked example of a first session — from
adoption through `wrap-up` — see **[`docs/getting-started.md`](docs/getting-started.md)**.

## Upgrading an already-adopted repo

**Pull the new kit files, then re-run `./init.sh`.** That is the supported upgrade
path, and it is safe to run any number of times:

- **Config** — `init.sh` migrates an older schema forward *in place*, only ever
adding missing keys. Your existing values are never guessed over. `kit.version`
records which generation you're on.
- **`paths.engines`** — probed from where your engines actually are, so a repo that
vendored them under `scripts/devkit/` is migrated to that path rather than a
wrong default.
- **Narrative docs** — a handoff or friction log you're actually using is left
byte-identical; only an unrendered skeleton is (re-)rendered.
- **Hooks** — reinstalled as a shim that execs the engine, so a hook stays current
with the engine rather than going stale as a copy.
- **Engines** — replace the files. Engines are **kit-owned**: everything
project-specific (review-bot markers, informational checks, CI policy, paths)
lives in `config/dev-model.yaml`, so you should never need to edit an engine to
adopt it. If you have, that's a bug — please report it.

### Agent runtime adapters

The workflow definitions under `docs/agentic-dev-kit/workflows/` are shared. The
Expand Down
53 changes: 53 additions & 0 deletions config/dev-model.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
# or edit this file directly.
# ─────────────────────────────────────────────────────────────────────────────

kit:
# Which generation of the kit's config schema this repo is on. `init.sh` stamps
# it and migrates an older config forward in place, so re-running `./init.sh`
# after pulling a kit update is the supported upgrade path. Never edit by hand:
# lowering it re-runs migrations that are already applied.
# 1 — original single-runtime schema (no `runtime:`, no `models.tiers`)
# 2 — runtime adapters + capability tiers + engine-facing review/CI config
version: 2

project:
# Human-readable project name, used in skill prompts and doc headers.
name: my-project
Expand Down Expand Up @@ -73,6 +82,43 @@ review:
fallback_commands:
claude: "/code-review"
codex: "/review"
# Everything below is read by scripts/pr_watch.py. It used to live as literals
# inside that engine, which meant adopting the kit required *editing the
# engine* — and an edited engine can never be replaced by a kit update. Keeping
# it here is what makes engines kit-owned and upgradable (Principle #10).
#
# Comment bodies matching any of these are auto-noise, not findings to act on.
# Matched case-insensitively as substrings. Keep the list tight — over-filtering
# hides a real review.
noise_markers:
- "<!-- this is an auto-generated comment: summarize by coderabbit"
- "<!-- this is an auto-generated comment: review in progress"
- "<!-- walkthrough_start -->"
- "actionable comments posted: 0"
- "<!-- linear-linkback -->"
# Bodies signalling the reviewer could not run. Deliberately NOT noise: these
# surface and block `done`, because a blocked bot is an action signal (run the
# configured fallback), never a silent review waiver.
unavailable_markers:
- "bugbot needs on-demand usage enabled"
- "review limit reached"
- "rate limited by coderabbit"
- "couldn't start this review"
- "review skipped"
- "no review credits"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
# Status checks that are advisory only and must never block `done`. A review
# bot's check can sit PENDING forever after a trivial follow-up commit; its real
# findings arrive as comments (which DO block). Matched case-insensitively
# against the check name.
informational_checks: [coderabbit]
# Whether a PR must have at least one real (non-informational) CI check before
# pr_watch will report `done`. True is the safe default: it stops an autonomous
# merge on a PR whose CI never ran. Set false for a repo with no CI at all —
# otherwise pr-watch can never converge and `dev_session.sh merge` always
# refuses. With false, `done` additionally requires current-head review evidence
# (it already does) — that receipt becomes the only quality gate, so set this
# deliberately.
require_ci: true

notify:
backend: slack # slack | none — where skills DM the operator
Expand Down Expand Up @@ -102,3 +148,10 @@ state:
# see scripts/lib/state_paths/. Those are kit constants, not adopter config; listed
# here only so the convention is discoverable. `dirname` is the top-level state dir.
dirname: state
# The unsandboxed-write guard skips a legitimate scheduled/CI writer, detected by
# env var. state_paths stays import-free (it must work from a git hook), so this is
# an ENV contract, not a value it reads from here — documented here for
# discoverability only:
# DEVKIT_CI_ENV_VARS comma-separated var names whose presence means "cron/CI".
# Default: JOB_NAME,CI,GITHUB_ACTIONS,GITLAB_CI,BUILDKITE
# Set it in your runner if your scheduler exports something else.
2 changes: 2 additions & 0 deletions docs/friction-log-archive.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- devkit-template: unrendered — ./init.sh renders this from docs/templates/. Delete this line to claim the file as yours. -->

# Friction Log Archive

Graduated friction entries live here after they have been routed to the tracker or
Expand Down
2 changes: 2 additions & 0 deletions docs/friction-log.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- devkit-template: unrendered — ./init.sh renders this from docs/templates/. Delete this line to claim the file as yours. -->

# Friction Log

> **Lean inbox (Principle #2 — the friction flywheel).** Friction surfaced during real
Expand Down
2 changes: 2 additions & 0 deletions docs/handoff-history.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- devkit-template: unrendered — ./init.sh renders this from docs/templates/. Delete this line to claim the file as yours. -->

# Handoff History

Archived session narratives from the living handoff. Keep active direction and the
Expand Down
2 changes: 2 additions & 0 deletions docs/handoff.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- devkit-template: unrendered — ./init.sh renders this from docs/templates/. Delete this line to claim the file as yours. -->

# my-project — Living Plan (Handoff)

> **Forward-looking handoff (Principle #1).** Read this at the start of every session
Expand Down
4 changes: 4 additions & 0 deletions docs/templates/friction-log-archive.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Friction Log Archive

Graduated friction entries live here after they have been routed to the tracker or
promoted into a repeated-pattern rule.
20 changes: 20 additions & 0 deletions docs/templates/friction-log.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Friction Log

> **Lean inbox (Principle #2 — the friction flywheel).** Friction surfaced during real
> use — a bug, an awkward workflow, a recurring annoyance — recorded the moment it's
> fresh, at session end. A periodic triage (`triage-friction-log`) reads new entries and
> routes each one: single incidents go **down** to the tracker; a genuine, multi-occurrence
> **pattern** graduates **up** into a rule or skill change. Route down by default, up only
> on repetition — so the flywheel self-regulates instead of ratcheting every week.
>
> Each entry: the observed issue, the date surfaced, a rough severity (**H**igh / **M**edium
> / **L**ow), and a proposed fix or next step. Link related PRs, commits, or tracker items
> when available. Graduated entries are swept to
> [`{{FRICTION_ARCHIVE}}`]({{FRICTION_ARCHIVE}}) so this file stays just the current
> inbox plus the most-recent graduation marker.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
>
> Tracker board: {{TRACKER_URL}}

## {{DATE}} — inbox

- **<one-line issue> (severity: <H/M/L>).** <what happened, and a proposed fix or next step.>
6 changes: 6 additions & 0 deletions docs/templates/handoff-history.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Handoff History

Archived session narratives from the living handoff. Keep active direction and the
next step in `{{HANDOFF}}`; this file is append-only history.

## Session log
26 changes: 26 additions & 0 deletions docs/templates/handoff.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# {{PROJECT_NAME}} — Living Plan (Handoff)

> **Forward-looking handoff (Principle #1).** Read this at the start of every session
> (`session-start`); update it at the end (`wrap-up`). This file — not an agent's
> memory, not a scratch note — is the single source of truth for what's done, in
> progress, and next.
>
> Older session blocks graduate to [`{{HANDOFF_HISTORY}}`]({{HANDOFF_HISTORY}}) once this
> file crosses its line budget (a warn-only tripwire — `{{ENGINE_DIR}}/check_doc_budget.py`).
> Session-scoped scratch plans are exactly that: scratch. This is the handoff.

Last updated: {{DATE}} — <one-line theme of the most recent session>

## Latest session — {{DATE}}

**Theme —** <what this session was about, in a line or two.>

- <what shipped>
- <what was decided>
- <what was learned>

▶ Next: <the single clearest next step — what the next `session-start` should pick up.>

______________________________________________________________________

> Older session entries live in [`{{HANDOFF_HISTORY}}`]({{HANDOFF_HISTORY}}).
Loading
Loading