Are you the author? Sign in to claim
Composable process framework for LLM-driven work at scale: durable process record, mechanical capture & priming, honest
The public, composable surface of ideate — a Claude Code plugin for AI-augmented software delivery.
ideate decomposes into three functions: a process record (the durable, auditable trail of what was decided and done — append-only, project-local, never curated or ranked by ideate itself), a knowledge graph (memory and retrieval over that trail — developed as a separate project, not part of this plugin), and a delegation board (how work is handed to and coordinated across agents — this plugin ships its LOCAL backend; the hosted, multi-person board is a future sibling service behind the same contract). ideate is deliberately non-prescriptive about workflow: it supplies primitives that fire mechanically, not a process you are told to follow, and it never blocks, redirects, or opines on what you do.
This package ships the Layer-0 floor: the append-only process record and the mechanical capture/priming wiring around it. Nothing here is optional workflow — every piece below fires without requiring an agent to remember to call it.
SessionEnd, PreCompact, SubagentStop,
TaskCompleted, and PostToolUse (on git commit) are wired in
hooks/hooks.json so records are captured mechanically as you work, with
zero required tool calls. Every ideate hook is non-blocking: it exits 0,
writes side effects and additionalContext only, and never blocks,
denies, or halts anything the host is doing.ideate-telemetry CLI.Node.js >= 22.5 must be installed and on your PATH. Claude Code ships as
a native binary and bundles no runtime, so the plugin's MCP server, hooks, and
CLIs — which run on Node and use the built-in node:sqlite — need Node
available. Install it from https://nodejs.org (or your package manager)
before installing the plugin.
There are two ways to wire this plugin into a Claude Code project. Both land
on the same MCP server and hooks/hooks.json — the manifests below are just
two different ways of pointing Claude Code at them. This section documents the
contracts (what each mechanism provides); it does not prescribe which one to
use or what workflow to run once installed.
This repo ships .claude-plugin/marketplace.json, a Claude Code
plugin-marketplace manifest listing this plugin (name: ideate, source: "./" — the repo root). From within Claude Code:
/plugin marketplace add ideate-ai/ideate
/plugin install ideate
This is the manifest-driven path — Claude Code resolves the plugin and wires
.mcp.json / hooks/hooks.json for you. On first launch the plugin runs a
one-time setup: because built output (dist/) is not committed, it installs
its single dependency and builds itself, then the MCP server, the mechanical
capture/priming hooks, and the CLIs are live. The first session may pause
briefly while that runs; later sessions start instantly. If Node is missing or
older than 22.5 (see Requirements above), the plugin prints a clear one-line
message and otherwise does nothing — it never blocks your session.
For a project that wants to point at this plugin directly rather than through the marketplace resolver:
Build the package: npm install && npm run build (compiles src/ to
dist/; dist/ is not committed). A marketplace install runs this for you
on first launch; for manual wiring you run it once yourself.
Add an MCP server entry to the consuming project's .mcp.json pointing at
the launcher, which runs the first-launch bootstrap before starting the
server:
{
"mcpServers": {
"ideate": {
"command": "sh",
"args": ["<path-to-this-plugin>/bin/ideate-mcp"]
}
}
}
This registers the three MCP verbs (record_append, record_read,
record_decision) described below.
Wire the mechanical capture hooks by pointing the consuming project's
host at this plugin's hooks/hooks.json. That file declares the actual
hook shape this plugin provides — SessionStart (priming via
bin/ideate-record prime), SubagentStart/SubagentStop, SessionEnd
(bin/ideate-record session-end), PreCompact, and PostToolUse on
git commit — each entry a command hook invoking either
${CLAUDE_PLUGIN_ROOT}/bin/ideate-record or one of the hooks/*.mjs
scripts. How a consuming project performs that wiring (copying the file,
referencing it, or another host-specific mechanism) is outside this
plugin's contract — only the shape of hooks/hooks.json itself is.
Prerequisites: Node >= 22.5.
npm install
npm run build # compiles src/ to dist/ (gitignored)
npm test # vitest (fork pool capped — see vitest.config.ts)
npm run test:fresh-copy runs scripts/fresh-copy-check.mjs, which copies
this directory to a scratch location with no surrounding project context and
re-runs install/build/test there — the mechanical proof that this package
stands alone.
The record core has exactly two transports over one implementation: three MCP tools, and a CLI. Both write through the same gated append-only store, so a record captured via one transport is indistinguishable from one captured via the other.
MCP verbs (registered by the ideate MCP server, dist/server.js):
record_append(kind, claim, verification_anchor?, scope?, content, task_id?)
— append one process record. Open-vocabulary kind (e.g. finding,
session-outcome, commit-boundary, …).record_read(scope?, limit?) — read records newest-first, optionally
filtered by a plain substring match against scope/kind/source. Unranked:
selection only, no scoring.record_decision(claim, rationale?, verification_anchor?, scope?, task_id?)
— sugar for record_append(kind="decision", ...); the ADR entry point.
The decision write is its capture — there is no separate decision store.ideate-record CLI (bin/ideate-record, the same gated core as a
standalone executable — this is what the capture hooks invoke):
ideate-record append --kind <k> --claim <c> [--anchor <a>] [--scope <s>] [--content <text>|-] [--task <id>]
— append one record directly; exits 1 on failure.ideate-record read [--scope <substring>] [--limit <n>] [--json] — print
records newest-first; exits 1 on failure.ideate-record session-end — reads a SessionEnd hook payload from stdin
and appends a recall-shaped session-outcome record. Hook path: always
exits 0 (a capture failure must never look like a hook failure to the
host).ideate-record prime [--scope <substring>] [--budget <n>] — print a
compact, unranked digest of the most recent records for hook
additionalContext. Hook path: always exits 0.The delegation board's LOCAL backend — the ratified work-state contract
implemented over SQLite in WAL mode. One sentence of model: work items carry
an opaque spec payload the board never parses (bring any methodology — a
plan document, a Spec Kit URI, a plain prompt); claims are
server-authoritative leases with fencing tokens — claim is an atomic
compare-and-set that succeeds only on an open item whose dependencies are
all done, leases expire (default hours-scale) so crashed workers can never
orphan work forever, and a stale token is rejected on
renew/complete/release after a reclaim. Every transition appends an
immutable audit event in the same transaction. For a solo user the
coordination features are degenerate (contention never occurs), never
absent — the same code paths a future hosted team would exercise, proven
by a contention suite that races real OS processes.
Eleven MCP verbs (same server, dist/server.js): work_create,
work_get, work_list, work_update_meta, work_claim, work_renew,
work_release, work_complete, work_cancel, work_reopen,
work_events. renew/complete/release take no actor — the token
proves identity, and the audit event carries the claim's actual holder.
ideate-work CLI (bin/ideate-work): the same eleven verbs as
subcommands plus a CLI-only sweep (the session-boundary expiry pass the
SessionStart/SessionEnd hooks trigger opportunistically). --json on
the read verbs. Board location: work_state.path in .ideate.json
(default .ideate-work/).
Board operations. The board is one SQLite file, board.db, under
work_state.path (workStatePath(), default .ideate-work/) — nothing
else lives there. Deleting that directory resets the board: every claim and
event is gone, and item state re-derives from nothing (there is no
recovery). This is safe to do on purpose because it is a DIFFERENT store
from the append-only process record (record.path, default
.ideate/record/) — deleting the board never touches the record, and vice
versa. board.db also carries a schema version (PRAGMA user_version, checked on every
open); if a build ever reports a version-mismatch error, that is
deliberate, not a bug — it means the file was written by a different
plugin version than the one reading it, and this project makes no
promises about migration timelines. Older, pre-versioning boards are
handled with a one-time grace (stamped on their next write) rather than
rejected outright.
One item's lifecycle — an example trace. The transcript below runs a work item end-to-end through the board (outputs trimmed for width). It illustrates the shape of the lifecycle — it does not prescribe a workflow, and every verb is equally available over MCP:
$ ideate-work create \
--title "Add retry backoff to the fetch client" \
--spec "<the work-item body — opaque to the board>" \
--spec-format "ideate/wi-v1" --human dan
{"id":"01KXBQDD7P…","status":"open","version":1,…}
$ ideate-work claim --id 01KXBQDD7P… --human dan --agent claude-coordinator
{"status":"in_progress","claim":{"holder":{"human":"dan","agent":"claude-coordinator"},
"claim_token":1,"lease_expires":"2026-07-12T21:53:58.767Z"},…}
# …the actual work happens here…
$ ideate-work complete --id 01KXBQDD7P… --token 1 \
--note "Exponential backoff added with jitter; full suite green."
{"status":"done","claim":null,…}
$ ideate-work events --id 01KXBQDD7P…
2026-07-12T17:53:45.206Z create actor=dan
2026-07-12T17:53:58.767Z claim actor=dan token=1
2026-07-12T17:55:58.126Z complete actor=dan token=1 note="NUL delimiters…"
Completing with a note is also a capture point: the note becomes an
append-only process record (kind work-completion, verification anchor
board:<item>#complete@<time>), retrievable through the record surface
like any other record:
$ ideate-record read --scope <item-id> --json
[{"kind":"work-completion",
"verification_anchor":"board:01KXBQDD7P…#complete@2026-07-12T17:55:58.126Z",
"claim":"Add retry backoff to the fetch client — Exponential backoff added…",…}]
SessionEnd, PreCompact, SubagentStop,
TaskCompleted, PostToolUse on git commit), session/subagent priming,
the capture-time secret-scanning gate, native telemetry counters, and the
work-state board's local backend (the eleven verbs above, with a
contention suite racing real OS processes as its correctness evidence).work_claims telemetry counter records the denominator,
but priming itself is mechanically disabled (work_state.claim_priming
config flag, default off, no environment override) pending further
validation. Same discipline as the rest of the deferred set:
planning-time gap identification (designed, not built) and per-prompt
priming (deferred). None of this plugin's shipped behavior depends on any
of these."private": true in package.json. It is distributed as a
Claude Code plugin — a git-source marketplace install that builds itself on
first launch — not published to npm, so private stays set.AGPL-3.0-only — see LICENSE.
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
Google's universal MCP server supporting PostgreSQL, MySQL, MongoDB, Redis, and 10+ databases
Official GitHub integration for repos, issues, PRs, and CI/CD workflows