skills/planning-dev-format/SKILL.md
Plan structure for code implementation work. Context, interfaces, data flow and behaviours without writing the implementation itself. Use during plan_mode when the work involves building or modifying code. Pairs with planning-guide for the overall planning methodology.
npx skillsauth add jitsusama/agentic-harness.pi planning-dev-formatInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Plans provide context and direction, not implementation.
Plans explain WHAT to build and WHY. Implementation (via TDD) determines HOW. The plan should give enough context that the person implementing can make intelligent decisions.
Reference the skills the implementer should load during implementation. Don't rewrite their content; just name them:
Follow TDD workflow (see code-tdd-guide skill) for implementation.
Follow code-style-standard skill for design and style.
Follow the user's writing voice and prose style guides for comments, docs and descriptions.
The implementer loads these skills and applies them. Plans don't need to repeat the guidance.
Include findings from investigation that help implementation understand the landscape:
Existing patterns:
System architecture:
Key constraints:
Design decisions already made:
Every plan must include a short progress tracking section near the top, right after context. This travels with the plan file so any agent picking it up in a fresh session knows the rules without loading external skills:
## Progress
Steps use checkboxes. Find the first unchecked step;
that's where to start. After completing a step, check it
off and commit the plan file update with the implementation
work. Do not start the next step until the current one is
checked off.
This section is short and imperative. It is not a suggestion; it is a standing order embedded in the document itself.
Break work into logical, independently reviewable units. No standard structure; let the work guide the split.
For each PR:
**PR N: [Purpose in 3-5 words]**
**What it does:** One paragraph explaining this PR's scope
**Why separate:** Why this is its own PR (if not obvious)
**Dependencies:** What must exist before this PR (other PRs, merged work)
**Files:** New files and modified files
Define what's publicly exposed and how it's called:
Method signatures with types:
Chunker.call(attempt: RedactionAttempt, partition_ids: Array<String> | nil) → Array<Hash>
What it returns:
Returns array of chunk hashes:
[
{ partition_ids: ["2025-01-01", "2025-01-02"], byte_size: 50000000, row_count: 100000 },
{ partition_ids: ["2025-01-03"], byte_size: 80000000, row_count: 150000 }
]
Integration points:
Called by: ChunkerJob (from state machine hook)
Calls: BigQuery INFORMATION_SCHEMA query
Side effects: None (pure function - returns data, doesn't mutate state)
Describe what flows through the system:
Format and fields:
Chunk Hash:
- partition_ids: Array of partition identifier strings (YYYY-MM-DD format)
- byte_size: Total logical bytes across partitions (Integer)
- row_count: Total rows across partitions (Integer)
Why this structure:
Passed through state transition to DMLQueryRunner.
Needs partition list for filtering, size data for monitoring.
Hash (not object) because state machines serialize to JSON.
Transformations:
Input: INFORMATION_SCHEMA returns partition_id as "YYYYMMDD"
Processing: Convert to Date, format as YYYY-MM-DD (iso8601)
Output: Array of YYYY-MM-DD strings
List behaviours to verify, high level, not full test code.
This is a coverage checklist, not a TDD implementation
sequence. Use flat bullets; don't group by happy path vs.
edge case vs. error. The implementer decides the TDD order
during implementation (see code-tdd-guide).
- No partition_ids (nil) → returns single chunk representing whole table
- Empty partition_ids array → same as nil
- Groups small partitions into single chunk when under limits
- Returns chunk with correct partition_ids, byte_size, row_count
- Splits into multiple chunks when partition count exceeds 4000
- Splits when accumulated bytes exceed MAX_BYTES_PER_CHUNK
- BigQuery connection error → raises with context
During TDD, more scenarios will emerge. This is the starting point.
Mark unknowns to resolve during implementation:
- Should we sort partitions by size before grouping?
- What if INFORMATION_SCHEMA returns null for byte_size?
- Do we need to handle partition_id format variations?
Don't guess answers; flag them for implementation to discover.
Common pattern (not prescriptive):
Service layer (pure business logic):
Chunker.call returns chunks arrayIntegration layer (wiring):
ChunkerJob calls service, then attempt.prepare_redaction!(chunks)This separation makes services testable without full state machine setup.
Don't write the full class/method body:
Bad:
def call
chunks = []
current_chunk = []
partition_info.each do |partition|
# ... 30 more lines
Good:
Groups partitions using bin-packing algorithm.
Respects MAX_PARTITIONS (4000) and MAX_BYTES (100GB) limits.
Don't write assertions and setup:
Bad:
test "groups partitions" do
partition_ids = ["2025-01-01", "2025-01-02"]
result = Chunker.call(attempt:, partition_ids:)
assert_equal 1, result.size
end
Good:
- Groups multiple small partitions into single chunk
Bad:
1. Loop through partition_ids
2. Query INFORMATION_SCHEMA for each
3. Create hash with results
4. Return array
Good:
Query INFORMATION_SCHEMA once with all partition_ids.
Map results to chunk hashes.
## PR 2: Chunker Service
**What it does:** Queries BigQuery partition sizes and groups
them into optimized chunks for DML execution.
**Why separate:** Core business logic independent of state
machine. Easier to test and understand.
**Dependencies:** None (queries BQ directly)
**Interface:**
Chunker.call(attempt: RedactionAttempt, partition_ids: Array<String> | nil) → Array<Hash>
Parameters:
- attempt: RedactionAttempt with table info and watermarks
- partition_ids: Array of YYYY-MM-DD strings or nil for unpartitioned
Returns: Array of chunk hashes (see Data Structures below)
Integration:
- Called by: ChunkerJob
- Calls: BigQuery INFORMATION_SCHEMA.PARTITIONS
- Side effects: None (pure function)
**Data Structures:**
Chunk Hash:
- partition_ids: Array<String> - partitions in this chunk
- byte_size: Integer - total bytes
- row_count: Integer - total rows
Constraints:
- Max 4000 partition_ids per chunk (BQ DML limit)
- Max 100GB byte_size per chunk (6hr query estimate)
**Test Scenarios:**
- No partition_ids (nil) → single chunk with empty partition_ids
- Single partition → one chunk with metadata
- Multiple small partitions → grouped into one chunk
- >4000 partitions → split into multiple chunks
- Accumulated bytes >100GB → split into multiple chunks
- INFORMATION_SCHEMA query fails → raise with context
When the plan was created with worktrees (the repos
parameter was provided during activation), include a cleanup
section at the end of the plan. List each worktree:
## Cleanup
After the work is merged or abandoned:
- [ ] Remove worktree: `git worktree remove <worktree-path>`
- [ ] Delete branch: `git branch -D <branch>`
The worktree paths are reported during activation. Replace
<branch> with whatever branch was created during
implementation.
Use during plan_mode when:
Work with planning-guide for overall planning process.
Use planning-dev-format for content structure.
development
Structure of a quest README and the documents that live under it: frontmatter shape, the four core and four optional body sections, emoji glyphs, ID format, alias notation, Cast bullets and Journey entries. Use when writing or editing a quest README, a plan, research, brief or report document under a quest. Pairs with quest-convention for choices like kind, promotion and reordering. Follow the prose-standard for voice.
tools
Operational conventions for the quest system: when to use a quest versus a subquest versus a sidequest, when to scaffold a plan or research document, how to reorder priorities, when to add optional sections, when to conclude versus retire, the resuscitate pattern. Use when driving the quest tool, deciding kind, promoting or parking work, or organising a project as quests. Pairs with quest-format for the on-disk shape.
development
Markdown structure rules: Title Case headings with their exceptions, the line-width target and its legitimate exceptions, reference-style links, fenced code blocks with language tags, tables and lists. Use when writing or editing any markdown file (README, AGENTS, docs, plans, skill files), or when adding a heading, link, table or code block. Owns markdown structure; pairs with prose-standard, which owns voice, grammar, spelling and punctuation.
tools
How to measure whether convention corrections keep recurring in the pi session logs, by category and by week. Use to record a baseline before the convention gates take effect and to re-run afterwards to confirm the recurring categories bend down. Pairs with the convention gates (pr-guardian, issue-guardian, commit-guardian, slack-integration) and the convention-context extension.