| name | planning-and-task-breakdown |
| description | Breaks work into ordered tasks (MeKnow-adapted onto OpenSpec). Use when you have an OpenSpec proposal or clear requirements and need to fill the change's design.md and tasks.md with implementable, verifiable units. Use when a task feels too large to start, when you need to estimate scope, or when parallel work is possible. |
| tags | [] |
Planning and Task Breakdown
Overview
Decompose work into small, verifiable tasks with explicit acceptance criteria. Good task breakdown is the difference between an agent that completes work reliably and one that produces a tangled mess. Every task should be small enough to implement, test, and verify in a single focused session.
In this repo (Mezon Mentor Bot / "MeKnow"), the plan lives in the OpenSpec change: architectural decisions go in .solo/spec/changes/cNNNN-<slug>/design.md, UI/visual design goes in ui.md (when the change has a user-facing surface), and the task list goes in tasks.md. All are generated by /solo:propose and refined here; /solo:plan-change groups them into test-first work-units and you tick tasks.md off during /solo:implement.
This is a polyglot repo — Python (uv workspace), Go (standalone go.mod modules, go 1.24), and TypeScript (apps/portal). A unit of work is py, go, or ts; the gate resolver (solo-gate) maps each touched path to its owning package and runs that toolchain's gates. Split tasks along package/capability seams so each unit lands in a single toolchain.
When to Use
- You have an OpenSpec proposal and need to break it into implementable units
- A task feels too large or vague to start
- Work needs to be parallelized across multiple agents or sessions
- You need to communicate scope to a human
- The implementation order isn't obvious
When NOT to use: Single-file changes with obvious scope, or when /solo:propose already produced well-defined tasks.
The Planning Process
Step 1: Enter Plan Mode
Before writing any code, operate in read-only mode:
- Read the change's
proposal.md and the relevant .solo/spec/specs/<capability>/spec.md baseline (and the linked docs/design/NNNN-*.md rationale)
- Read the relevant packages and identify existing patterns and conventions
- Map dependencies between components
- Note risks and unknowns
Do NOT write code during planning. The output is design.md + tasks.md, not implementation. (/solo:explore is the dedicated think-only mode if you need to investigate first.)
Step 2: Identify the Dependency Graph
Map what depends on what. A MeKnow change typically flows from the data model and policy outward through the retrieval runtime to the answer surface:
data model / migration (packages/rag-core, apps/backend/migrations)
│
├── BotPolicy / stage definition (packages/bot-policy)
│ │
│ ├── retrieve_kb tool + ACL (packages/rag-core, kb-mcp)
│ │ │
│ │ └── retrieval runtime: synthesize/cite/filter (packages/agent-core)
│ │ │
│ │ ├── worker / API surface (apps/backend, apps/worker-*)
│ │ └── portal types (apps/portal — generated from OpenAPI)
│ │
│ └── eval-harness golden-set gates (benchmarks/gates, tests/fixtures)
│
└── end-to-end check (benchmark gates + cross-tenant isolation tests)
Implementation order follows the dependency graph bottom-up: build foundations first. A unit that touches Go (packages/mello-sdk, apps/worker-mello) or TS (apps/portal) is its own seam.
Step 3: Slice Vertically
Instead of building all the schema, then all the runtime, then all the API wiring — build one complete path at a time:
Bad (horizontal slicing):
Task 1: Build entire data model
Task 2: Build all retrieval stages
Task 3: Build all API endpoints
Task 4: Connect everything
Good (vertical slicing):
Task 1: BotPolicy stage definition for the new capability (py: packages/bot-policy)
Task 2: retrieve_kb returns ACL-scoped, tenant-isolated chunks (py: packages/rag-core)
Task 3: synthesize/cite/filter produce a cited answer or refuse on no_citations (py: packages/agent-core)
Task 4: Backend exposes it via OpenAPI; portal consumes the generated types (py + ts)
Each vertical slice delivers working, testable functionality and is backed by a benchmark gate where it asserts a guarantee (faithfulness, citation accuracy, tenant isolation).
Step 4: Write Tasks
Each task in tasks.md follows this structure. State the unit's toolchain so the gate resolver knows which gates apply:
## Task [N]: [Short descriptive title] (toolchain: py | go | ts)
**Description:** One paragraph explaining what this task accomplishes.
**Acceptance criteria:**
- [ ] [Specific, testable condition]
- [ ] [Specific, testable condition]
**Verification (resolver-selected gates for this unit's toolchain):**
- [ ] Python (member dir D): `uv --directory D run ruff check .` · `ruff format --check .` · `uv --directory D run pyright` · `uv --directory D run python -m pytest -q`
- [ ] Go (module dir M): `go build ./...` · `go vet ./...` · `go test -race ./...`
- [ ] TS (apps/portal): `pnpm typecheck` · `pnpm lint` · `pnpm test`
- [ ] Touched packages build/import: `uv --directory D run python -c 'import <pkg>'` / `go build ./...` / `pnpm build` as applicable
- [ ] Benchmarks (py/bench changes): `bash benchmarks/ci-free-gates.sh`
- [ ] Always: `solo-spec validate "<change>" --strict`
- [ ] Manual check: [what to verify]
**Dependencies:** [Task numbers this depends on, or "None"]
**Files likely touched:**
- `packages/rag-core/src/.../retrieve.py`
- `packages/rag-core/tests/test_retrieve.py`
**Estimated scope:** [Small: 1-2 files | Medium: 3-5 files | Large: 5+ files]
Step 4b: UI Tasks
When the change has a ui.md (i.e., a user-facing surface), first read the project's
existing design documentation — .solo/spec/patterns/ux-patterns.md, DESIGN.md, or
design skills — to understand the UX patterns and visual concepts the implementation
must follow. This ensures tasks reference real project conventions, not invented values.
Each UI task should reference the relevant ui.md sections and enumerate all UI states,
plus the project's UX patterns to follow:
## Task [N]: SearchResultList component with all states (toolchain: ts)
**Description:** Build the SearchResultList component with loading skeleton,
empty-state message, error state with retry, and populated card list.
Follow ui.md → Component Tree for the hierarchy and ui.md → UI States for
the behavior of each state. Follow the project's established UX patterns for
loading (skeleton), empty state (illustration + message + CTA), and error
display (inline error + retry).
**Follow these UX patterns from the project (see DESIGN.md / ux-patterns.md):**
- Loading pattern: skeleton screens, not spinners
- Empty state pattern: illustration + message + suggested action
- Error pattern: inline error box with retry button
- Data display pattern: card grid with slide-in detail panel
- Responsive pattern: 3-col → 2-col → 1-col at project breakpoints
**Acceptance criteria:**
- [ ] Loading: skeleton renders while data is being fetched (per project loading pattern)
- [ ] Empty: "No results found" with illustration + suggested action (per project empty state pattern)
- [ ] Error: error message + RetryButton on fetch failure (per project error pattern)
- [ ] Populated: renders ResultCard for each result item
- [ ] Edge: handles 0, 1, and 1000+ results without layout breakage
- [ ] Responsive: layout adapts at breakpoints specified in ui.md (per project responsive pattern)
- [ ] Accessibility: keyboard navigation + ARIA labels per ui.md
- [ ] Style: uses project's established card pattern (spacing, typography, border radius)
Step 5: Order and Checkpoint
Arrange tasks so that:
- Dependencies are satisfied (build foundation first)
- Each task leaves the system in a working state (the unit's toolchain gates pass)
- Verification checkpoints occur after every 2-3 tasks
- High-risk tasks are early (fail fast — e.g. ACL scoping, tenant isolation, citation refusal)
Add explicit checkpoints:
## Checkpoint: After Tasks 1-3
- [ ] Each touched toolchain's gates pass (resolver-selected: ruff/pyright/pytest, go vet/test -race, pnpm typecheck/lint/test)
- [ ] Touched packages build/import cleanly
- [ ] `bash benchmarks/ci-free-gates.sh` green; citation + tenant-isolation gates pass
- [ ] `solo-spec validate "<change>" --strict`
- [ ] Review with human before proceeding
Task Sizing Guidelines
| Size | Files | Scope | Example |
|---|
| XS | 1 | Single function or config change | Add a stage knob to a BotPolicy |
| S | 1-2 | One handler or function | Add an OpenAPI endpoint + generated portal type |
| M | 3-5 | One feature slice | New retrieval stage in packages/agent-core |
| L | 5-8 | Multi-component feature | New worker + its API surface + eval gate |
| XL | 8+ | Too large — break it down further | — |
If a task is L or larger, break it into smaller tasks. An agent performs best on S and M tasks.
When to break a task down further:
- It would take more than one focused session (roughly 2+ hours of agent work)
- You cannot describe the acceptance criteria in 3 or fewer bullet points
- It touches two or more independent subsystems (e.g.,
retrieve_kb and the OpenAPI surface)
- It spans more than one toolchain (a
py change and a ts change) — split into one unit per language
- You find yourself writing "and" in the task title (a sign it is two tasks)
Plan Document (design.md) Template
Record architecture decisions in the change's design.md; keep the actual task list in tasks.md. For changes with a user-facing surface, also create ui.md in the same change directory with wireframes, component tree, UI states, and visual decisions. See the ui-design skill for the template and process.
# Design: [Feature/Change Name]
## Overview
[One paragraph summary of what we're building and which capability it changes]
## Architecture Decisions
- [Key decision 1 and rationale — e.g. why embedded MCP transport, not ACP/A2A in the loop]
- [Key decision 2 and rationale — e.g. new BotVersion row + prompt file, not interpreter code]
## Dependency Graph
[Bottom-up ordering of packages, noting the toolchain (py/go/ts) of each unit]
## Risks and Mitigations
| Risk | Impact | Mitigation |
|------|--------|------------|
| Cross-tenant data leak | High | tenant_id on every query + cache key; tenant-isolation-test.sh gate |
| Ungrounded answer | High | filter stage `refuse_if: no_citations`; citation-accuracy-gte.sh gate |
## Open Questions
- [Question needing human input]
Parallelization Opportunities
When multiple agents or sessions are available:
- Safe to parallelize: Independent feature slices in different packages, units in different toolchains (a
py retrieval change and a ts portal change), tests for already-implemented behavior, documentation
- Must be sequential: Alembic migrations, changes to shared data-model tables, anything that mutates
BotVersion/KBVersion lineage (versions are append-only — a new child, never in-place)
- Needs coordination: Features that share the OpenAPI contract (backend generates the spec; portal types are generated, never hand-written) or the
kb.* MCP contract — define the contract first, then parallelize
Common Rationalizations
| Rationalization | Reality |
|---|
| "I'll figure it out as I go" | That's how you end up with a tangled mess and rework. 10 minutes of planning saves hours. |
| "The tasks are obvious" | Write them in tasks.md anyway. Explicit tasks surface hidden dependencies and forgotten edge cases. |
| "Planning is overhead" | Planning is the task. Implementation without a plan is just typing. |
| "I can hold it all in my head" | Context windows are finite. design.md/tasks.md survive session boundaries and compaction. |
Red Flags
- Starting implementation without a written
tasks.md
- Tasks that say "implement the feature" without acceptance criteria
- No verification steps (the unit's resolver-selected gates) in a task
- A single task spanning Python, Go, and TS at once
- All tasks are XL-sized
- No checkpoints between tasks
- Dependency order isn't considered (API surface before its data model)
Verification
Before starting implementation, confirm:
MeKnow notes
- The plan is OpenSpec: decisions go in
.solo/spec/changes/cNNNN-<slug>/design.md,
UI/visual design in ui.md (when applicable), the ordered task list in tasks.md.
/solo:propose scaffolds them; you refine them here; /solo:plan-change groups them
into work-units and you tick tasks.md during /solo:implement. This skill is the
PLAN+TASKS half of spec-driven-development.
- Order tasks bottom-up along the pipeline (data model → BotPolicy → retrieve_kb/ACL →
synthesize/cite/filter → worker/API → portal), and let the benchmark gates
(
benchmarks/ci-free-gates.sh, faithfulness/citation/latency/tenant-isolation) be
the end-to-end checkpoint.
- Split units along package/capability seams across languages: a unit is
py,
go, or ts. The gate resolver groups units by toolchain and runs that toolchain's
gates (Python: ruff/pyright/pytest; Go: go vet / test -race; TS: pnpm typecheck/lint/test).
- Keep the invariants in acceptance criteria:
tenant_id on every table/query/cache
key/log line; citations mandatory (refuse_if: no_citations); temperature == 0 on
synthesize/cite/filter; ACL enforced server-side in retrieve_kb (never trust
model-supplied identity); versions append-only (BotVersion/KBVersion — new
child, never mutate); MCP is the internal tool boundary (no LangChain); new
bot/capability = a new BotVersion/BotPolicy row + prompt file, not code.
- Verification evidence for each task belongs under
.solo/spec/changes/<name>/evidence/. The LLM-tier gates (faithfulness >= 0.85,
citation accuracy >= 0.95, p95 latency <= 12s) are the product's real contract;
reference the backing gate script from any scenario that asserts a guarantee.