CtrlK
BlogDocsLog inGet started
Tessl Logo

work-decomposition

Turn an accepted kitsoki proposal (or an epic + its children) into a validated, reviewed YAML decomposition of right-sized agent briefs. Use when the user wants to decompose work into briefs, "break this proposal into tickets/tasks", produce a decomposition.yaml, or check out the brief-manifest shape from docs/proposals/work-decomposition.md before that pipeline is built as a story. Drives discovery → manifest → deterministic structural lint → adversarial feasibility/completeness review, by hand.

SKILL.md
Quality
Evals
Security

Work decomposition

This skill is the Claude-driven version of the pipeline proposed in docs/proposals/work-decomposition.md: it takes an accepted proposal (or an epic + its linked children) and produces a decomposition.yaml of agent briefs — structurally validated and adversarially reviewed — so you can check out the manifest shape and the slicing quality before the stories/decompose/ story is built.

The same discipline the proposal encodes applies here, just run by you instead of the engine: the interpretive decisions (how to slice, is it feasible, is it complete) are your judgment; the structural truth (unique ids, acyclic DAG, coverage, path bounds) is a deterministic script whose exit code is the gate — the kitsoki moat: separate interpretation from deterministic execution.

Scope: this decomposes an accepted proposal. Authoring/scoping the proposal itself is the proposal-authoring skill. Implementing a single brief is the stories/implementation/ pipeline (and kitsoki-story-authoring for story-layer work). This skill stops at a reviewed decomposition.yaml.

The output shape — the heart

The deliverable is a manifest matching schemas/decomposition.json: a coverage_note plus a briefs[] array, each brief carrying id, title, kind, goal, scope[], depends_on[], acceptance[], test_plan, agent_brief (and optional risk).

coverage_note: >
  These four briefs fully cover the proposal: #1 adds the engine seam, #2 the
  story that uses it, #3 the TUI surface, #4 the docs+flow fixtures. Nothing in
  the proposal's "What changes" is left unowned, and no two briefs touch the
  same files.
briefs:
  - id: engine-once-flag
    title: Add `once:` guard to room on_enter effects
    kind: runtime
    goal: A room with `once: true` re-runs its on_enter effects at most once per visit, surviving /reload.
    scope: ["internal/machine/", "internal/app/imports.go"]
    depends_on: []
    acceptance:
      - "A reloaded room with once:true does not re-fire its on_enter oracle call"
      - "Existing rooms without once: behave unchanged"
    test_plan: "internal/machine/machine_test.go: new TestOnceGuard; existing flow fixtures stay green."
    agent_brief: >
      Implement an engine-level `once:` boolean on room on_enter effect lists...
      (self-contained — everything the implementer needs, no external context).
    risk: medium

kind ∈ story | runtime | tui | tracing | test | docs. scope globs are the write boundary for the brief; new-file briefs legitimately point at paths that don't exist yet (the validator bounds them rather than requiring a match).

The loop

Run these phases in order. They mirror the proposal's rooms; each gate must pass before the next.

1. Load the source

Resolve the source the user named (a docs/proposals/<slug>.md, or an epic). Read the full body. Detect epic vs. focused: an epic has **Kind:** epic and a Slices table over linked children — if so, read every linked child proposal too, and warn (non-fatal) on any child file that's missing or renamed. Confirm back to the user: the title, kind, and (for an epic) the child count, so they know you pointed at the right thing.

2. Discovery — sharpen the scope (interactive)

Before slicing, have a short conversation to pin the constraints a static read can't give you:

  • What must be sequential vs. what can be parallel?
  • The test strategy (flow fixtures? go tests? manual checks?).
  • Risk areas and explicit non-goals (often already in the proposal — confirm, don't re-derive).
  • Any files/subsystems that are off-limits or owned elsewhere.

Capture the answers in .context/decompose-<slug>-scope.md (transient working notes, per CLAUDE.md). Don't skip this even when the proposal looks complete — the slicing quality lives here. Stop when you can state the slicing rationale in two sentences.

3. Decompose — emit the brief manifest

Produce the manifest. Slicing rules:

  • A brief is right-sized when it has one coherent goal, fits one implementer's head, and could land alone or behind one named dependency. Cut along kind boundaries first (runtime substrate → story → tui, tracing where its events are produced), then along shippable units within a kind.
  • depends_on is the real build order — be honest; a missing edge is what the reviewer and the board will trip on.
  • No file double-ownership: two briefs' scope globs should not overlap on the same file. Overlap is a slicing bug.
  • agent_brief is self-contained — the implementer agent gets only that text plus the ticket fields, not this conversation. Spell out the approach, the key files, and the done-condition.
  • The coverage_note is your completeness claim — write it to be attacked: state explicitly how the briefs together cover every item in the proposal's "What changes", with nothing unowned.

Write it to .artifacts/decompose/<slug>/decomposition.yaml (generated artifact, not committed — CLAUDE.md).

4. Validate — the deterministic gate

Run the bundled validator. Its exit code is the gate — do not proceed to review on a non-zero exit:

python3 .agents/skills/work-decomposition/scripts/validate_decomposition.py \
    .artifacts/decompose/<slug>/decomposition.yaml --repo-root .

It checks schema shape, unique ids, dangling depends_on, an acyclic dependency DAG, scope paths bounded inside the repo (parent dir exists), and non-empty acceptance + test_plan per brief. On failure: fix the manifest (go back to step 3 with the errors as the brief) and re-run until clean. This gate has teeth independent of any LLM — trust it over your own read.

There is also a Starlark equivalent (validate_decomposition.star) that covers the pure-logic checks (unique ids, acyclic DAG, acceptance/test_plan) and can be called via host.starlark.run from a story room — pass the parsed manifest as inputs.manifest. It does not cover JSON-schema shape or scope-path bounds (those need filesystem access and the jsonschema library; use the Python script for those).

5. Adversarial review — feasibility + completeness

Now switch hats and attack your own manifest as a skeptic (or, for a real second opinion, spawn a sub-agent with the Agent tool to do it independently — that's closer to the proposal's decomp_adversary):

  • Per brief: is this actually buildable as scoped? Are its deps right and complete? Is anything impossible, hand-wavy, or secretly two briefs?
  • Across briefs: do they fully cover the proposal — attack the coverage_note, name anything in "What changes" that no brief owns. Is there file overlap / double-ownership?
  • Default to revise when uncertain. A confident "looks good" with no attempted refutation is not a review.

Emit a verdict: {verdict: accept | revise, reason, questions[]}. On revise, fold questions[] back into step 3 and re-run validate + review. Budget the loop (≈5 passes); if it won't converge, stop and tell the user why — unconverged slicing is a signal the proposal isn't decomposable as written.

6. Hand back

On accept, present:

  • the path to the validated decomposition.yaml,
  • a one-line board: status · id — title (deps) per brief in dependency order, with the parallelizable briefs called out,
  • the coverage_note and the review verdict + reason.

Note for the user that each brief is shaped to become a ticket the stories/implementation/ pipeline can build (id/title/body = agent_brief + acceptance + scope + test_plan) — which is exactly what the proposal's dispatch room will mint once the story ships.

Quick reference

StepMechanismGate
Load proposal/epicread docs/proposals/<slug>.md (+ children)right source confirmed
Discoveryshort conversation → .context/ scope noteslicing rationale in 2 sentences
Decomposeemit manifest → .artifacts/decompose/<slug>/decomposition.yamlschema-shaped
Validatevalidate_decomposition.py (CLI) or host.starlark.run validate_decomposition.star (story room)exit code 0 / ok: true
Reviewskeptic pass (or sub-agent)verdict: accept
Hand backboard + coverage note + verdict—

Maintenance

Codex discovers this skill directly. Refresh the project-local Claude Code symlink after adding or moving skills:

make setup

When the stories/decompose/ story from the proposal ships, the schemas/decomposition.json here and stories/decompose/schemas/decomposition.json should stay identical — they're the same contract; reconcile them rather than letting them drift.

Repository
constructorfabric/Kitsoki
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.