🐱 Medium-horizon agent planning MCP server
9plan docs worked-example.md
19 kB
Markdown
at main

9plan Worked Example: Ghost Blog Application #

A complete end-to-end walkthrough showing how 9plan manages a realistic multi-phase project from bootstrap to completion.


The Task #

Goal: Build a simple blog application powered by the Ghost CMS API. The app should:

  • Authenticate with Ghost's Content API
  • Fetch and display blog posts
  • Support pagination
  • Cache responses for performance

Why this example: It involves multiple components with dependencies, requires decomposition, and demonstrates cross-branch coordination.


Phase 1: Bootstrap #

User Initiates Session #

User: I want to build a Ghost-powered blog app. It needs auth, 
      post fetching with pagination, and caching.

Agent Creates Session #

Agent calls: 9plan_session_create
  task_description: "Build Ghost-powered blog application with authentication,
                     post fetching, pagination, and response caching"

Response: 
  [Session: amber-quiet-river]
  Session created: amber-quiet-river
  Directory: /Users/dev/.9plan/sessions/amber-quiet-river

Agent Decomposes into Initial Plans #

The agent identifies three major components and their dependencies:

┌─────────────────────────────────────────────────────┐
│                   Blog App                          │
├──────────────┬──────────────┬──────────────────────┤
│  Ghost API   │    Cache     │    Display Layer     │
│   Client     │   System     │    (Posts + Paging)  │
├──────────────┼──────────────┼──────────────────────┤
│ Outputs:     │ Inputs:      │ Inputs:              │
│ - auth'd     │ - API client │ - API client         │
│   client     │ Outputs:     │ - Cache system       │
│              │ - cache API  │ Outputs:             │
│              │              │ - working app        │
└──────────────┴──────────────┴──────────────────────┘

Critical moment: Right now, all three branches are visible. The agent captures dependencies:

  • Cache System needs Ghost API Client's outputs
  • Display Layer needs both Ghost API Client AND Cache System outputs

Adding Plans to Queue #

Agent calls: 9plan_queue_add
  context: "Building Ghost blog app. This is the foundational component that
            all other parts depend on. Must complete first."
  goal: "Create authenticated Ghost API client module"
  inputs: "- Ghost API credentials: provided by user or environment"
  outputs: "- ghost_client module: authenticated client instance with methods
             for getPosts(), getPost(id), with proper error handling"
  approach: "1. Set up Ghost Content API authentication using API key
             2. Create client wrapper with typed methods
             3. Implement error handling for auth failures and API errors
             4. Export configured client instance"
  success_criteria: "- Client successfully authenticates with Ghost API
                     - getPosts() returns post array
                     - getPost(id) returns single post
                     - Auth errors throw descriptive exceptions"
  position: back

Response:
  [Session: amber-quiet-river]
  Plan added: k7f3m
  Path: /Users/dev/.9plan/sessions/amber-quiet-river/plans/k7f3m.txt
  Queue position: 1
Agent calls: 9plan_queue_add
  context: "Building Ghost blog app. This provides caching to reduce API calls
            and improve performance. Depends on Ghost API client."
  goal: "Implement response caching system"
  inputs: "- ghost_client module: from Ghost API Client work"
  outputs: "- cache module: wrap-able caching layer with get/set/invalidate
           - cached_client: ghost_client wrapped with caching"
  approach: "1. Design cache interface (get, set, invalidate, TTL)
             2. Implement in-memory cache with configurable TTL
             3. Create wrapper that checks cache before API calls
             4. Add cache invalidation hooks"
  success_criteria: "- Second call to same endpoint returns cached data
                     - Cache respects TTL settings
                     - Manual invalidation works
                     - Cache misses fall through to API"
  position: back

Response:
  [Session: amber-quiet-river]
  Plan added: m2x9p
  Queue position: 2
Agent calls: 9plan_queue_add
  context: "Building Ghost blog app. This is the user-facing component that
            displays posts with pagination. Depends on both API client and cache."
  goal: "Build post display layer with pagination"
  inputs: "- cached_client: from Cache System work
           - ghost_client module: from Ghost API Client (fallback)"
  outputs: "- Working blog display: renders posts with next/prev navigation"
  approach: "1. Create post list component with pagination controls
             2. Implement page state management
             3. Connect to cached client for data fetching
             4. Add loading and error states"
  success_criteria: "- Posts display in paginated list
                     - Next/prev navigation works
                     - Loading states show during fetch
                     - Errors display gracefully"
  position: back

Response:
  [Session: amber-quiet-river]
  Plan added: p4r2k
  Queue position: 3

State After Bootstrap #

Queue: [k7f3m, m2x9p, p4r2k]

Files:

amber-quiet-river/
├── session.db
└── plans/
    ├── k7f3m.txt   # Ghost API Client
    ├── m2x9p.txt   # Cache System
    └── p4r2k.txt   # Display Layer

k7f3m.txt contents:

# Context
Building Ghost blog app. This is the foundational component that all other
parts depend on. Must complete first.

# Goal
Create authenticated Ghost API client module

# Inputs
- Ghost API credentials: provided by user or environment

# Outputs
- ghost_client module: authenticated client instance with methods for 
  getPosts(), getPost(id), with proper error handling

# Approach
1. Set up Ghost Content API authentication using API key
2. Create client wrapper with typed methods
3. Implement error handling for auth failures and API errors
4. Export configured client instance

# Success Criteria
- Client successfully authenticates with Ghost API
- getPosts() returns post array
- getPost(id) returns single post
- Auth errors throw descriptive exceptions

# Notes

Phase 2: First Plan Execution #

Agent Pulls First Plan #

Agent calls: 9plan_queue_pull

Response:
  [Session: amber-quiet-river]
  Active plan: k7f3m
  Path: /Users/dev/.9plan/sessions/amber-quiet-river/plans/k7f3m.txt
  
  Review the plan file for full context. Check for ambiguities before
  starting execution. If inputs reference other plans, use 
  9plan_history_search to find their outputs.

Agent Reads Plan File #

Agent uses filesystem tools to read k7f3m.txt, reviews the content, and proceeds with execution.

Mid-Execution Checkpoint #

After implementing the basic client structure, agent updates Notes:

k7f3m.txt (updated):

# Notes
[2024-01-15 14:30] Progress checkpoint:
- Created ghost-client.ts with GhostClient class
- Implemented constructor with API key validation
- getPosts() method complete, tested against live API
- Remaining: getPost(id), error handling improvements

Discovering Subwork #

While implementing, agent realizes error handling is complex enough to warrant its own focus. But it's small—agent decides to complete it within this plan rather than decompose.

Completing the Plan #

Agent calls: 9plan_plan_complete
  outcome: "Created ghost_client module in src/lib/ghost-client.ts.
           
           Exports:
           - GhostClient class with constructor(apiKey, apiUrl)
           - getPosts(options?: {limit, page}) → Post[]
           - getPost(id: string) → Post
           
           Error handling:
           - GhostAuthError for 401/403 responses
           - GhostNotFoundError for 404 responses  
           - GhostAPIError for other failures
           
           Tested against live Ghost instance, all methods working."

Response:
  [Session: amber-quiet-river]
  Plan k7f3m completed and indexed.
  
  Queue status: 2 plans remaining
  Next: Use 9plan_queue_pull to continue

State After First Completion #

Queue: [m2x9p, p4r2k]

Database: k7f3m now in history, searchable

Files:

amber-quiet-river/
├── session.db          # k7f3m indexed in history
└── plans/
    ├── m2x9p.txt       # Cache System
    └── p4r2k.txt       # Display Layer

Phase 3: Dependency Resolution #

Agent Pulls Cache System Plan #

Agent calls: 9plan_queue_pull

Response:
  [Session: amber-quiet-river]
  Active plan: m2x9p
  Path: /Users/dev/.9plan/sessions/amber-quiet-river/plans/m2x9p.txt

Agent Resolves Input Dependency #

The plan's Inputs field says: ghost_client module: from Ghost API Client work

Agent calls: 9plan_history_search
  query: "ghost_client module Ghost API"

Response:
  [Session: amber-quiet-river]
  Found 1 matching plan:
  
  Plan k7f3m: "Create authenticated Ghost API client module"
  Outcome: Created ghost_client module in src/lib/ghost-client.ts.
           Exports GhostClient class with getPosts(), getPost() methods...

Agent now knows where to import from and what interface to expect.

Execution and Completion #

Agent implements the cache system, wrapping the Ghost client.

Agent calls: 9plan_plan_complete
  outcome: "Created caching layer in src/lib/cache.ts.
           
           Exports:
           - Cache<T> class with get(key), set(key, value, ttl?), invalidate(key)
           - createCachedClient(ghostClient) → returns proxied client
           
           The cached_client wraps GhostClient from src/lib/ghost-client.ts.
           Default TTL: 5 minutes. Configurable via Cache constructor.
           
           Cache hits logged to console for debugging."

Phase 4: Plan Decomposition #

Agent Pulls Display Layer Plan #

Agent calls: 9plan_queue_pull

Response:
  [Session: amber-quiet-river]  
  Active plan: p4r2k
  Path: /Users/dev/.9plan/sessions/amber-quiet-river/plans/p4r2k.txt

Agent Decides to Decompose #

After reviewing the plan, agent realizes "Display Layer with pagination" is too large for a focused session. It involves:

  • UI component structure
  • State management
  • Data fetching integration
  • Loading/error states

Agent decides to decompose.

Checkpointing Before Decomposition #

Agent updates p4r2k.txt Notes section:

# Notes
[2024-01-15 16:00] Decomposing into subplans:
- p4r2k-1: Post list component (UI structure)
- p4r2k-2: Pagination state management  
- p4r2k-3: Integration (connect data + UI)

Will defer this plan after adding children.

Adding Subplans (Reverse Order for Correct Execution) #

Agent calls: 9plan_queue_add
  context: "Building Ghost blog app display layer. This is the final integration
            step that connects the data layer to the UI components."
  goal: "Integrate data fetching with UI components"
  inputs: "- PostList component: from post list component work
           - usePagination hook: from pagination state work
           - cached_client: from Cache System work"
  outputs: "- Working integrated display: all pieces connected and functional"
  approach: "1. Import PostList and usePagination into main page
             2. Connect usePagination to cached_client.getPosts()
             3. Pass paginated data to PostList
             4. Wire up navigation callbacks"
  success_criteria: "- Page loads and displays posts
                     - Pagination controls navigate correctly
                     - Loading states display during transitions"
  position: front

Response: Plan added: j8n2q, position 1
Agent calls: 9plan_queue_add
  context: "Building Ghost blog app display layer. This handles the pagination
            logic separately from UI rendering."
  goal: "Implement pagination state management"
  inputs: "(none - self-contained logic)"
  outputs: "- usePagination hook: manages page state, provides next/prev handlers"
  approach: "1. Create usePagination React hook
             2. Track current page, total pages, loading state
             3. Provide nextPage(), prevPage(), goToPage(n) handlers
             4. Handle edge cases (first page, last page)"
  success_criteria: "- Hook tracks page state correctly
                     - Navigation handlers update state
                     - Edge cases don't cause invalid states"
  position: front

Response: Plan added: r3t7w, position 1
Agent calls: 9plan_queue_add
  context: "Building Ghost blog app display layer. This is the presentational
            component, separate from data fetching logic."
  goal: "Create PostList UI component"
  inputs: "(none - receives data via props)"
  outputs: "- PostList component: renders array of posts with pagination controls"
  approach: "1. Create PostList component accepting posts array prop
             2. Add PostCard subcomponent for individual posts
             3. Add pagination controls (prev/next buttons)
             4. Style with basic CSS"
  success_criteria: "- Component renders post list from props
                     - Pagination controls render and fire callbacks
                     - Empty state handled gracefully"
  position: front

Response: Plan added: x5k9m, position 1

Deferring Parent Plan #

Agent calls: 9plan_plan_defer
  reason: "Decomposed into subplans: x5k9m (PostList UI), r3t7w (pagination state), 
           j8n2q (integration). Will aggregate child outcomes when re-pulled."
  position: back

Response:
  [Session: amber-quiet-river]
  Plan p4r2k deferred to back of queue.
  Reason recorded in Notes.

State After Decomposition #

Queue: [x5k9m, r3t7w, j8n2q, p4r2k]

The subplans are at front in correct execution order. Parent p4r2k is at back, waiting to aggregate.

p4r2k.txt Notes (updated by server):

# Notes
[2024-01-15 16:00] Decomposing into subplans:
- p4r2k-1: Post list component (UI structure)
- p4r2k-2: Pagination state management
- p4r2k-3: Integration (connect data + UI)

Will defer this plan after adding children.

[2024-01-15 16:05] Deferred: Decomposed into subplans: x5k9m (PostList UI), 
r3t7w (pagination state), j8n2q (integration). Will aggregate child outcomes 
when re-pulled.

Phase 5: Executing Child Plans #

Agent executes x5k9m, r3t7w, and j8n2q in sequence. Each follows the normal cycle:

  1. Pull
  2. Resolve inputs via history search
  3. Execute
  4. Complete with descriptive outcome

After all three complete:

Queue: [p4r2k]

History: k7f3m, m2x9p, x5k9m, r3t7w, j8n2q (all searchable)


Phase 6: Parent Aggregation #

Agent Pulls Parent Plan Again #

Agent calls: 9plan_queue_pull

Response:
  [Session: amber-quiet-river]
  Active plan: p4r2k
  Path: /Users/dev/.9plan/sessions/amber-quiet-river/plans/p4r2k.txt

Agent Reads Notes, Sees Decomposition Record #

From the Notes section, agent sees this plan was decomposed and identifies child plan IDs.

Agent Retrieves Child Outcomes #

Agent calls: 9plan_history_get
  plan_id: x5k9m

Response: [Full plan with outcome: "Created PostList component..."]
Agent calls: 9plan_history_get  
  plan_id: r3t7w

Response: [Full plan with outcome: "Created usePagination hook..."]
Agent calls: 9plan_history_get
  plan_id: j8n2q

Response: [Full plan with outcome: "Integrated all components..."]

Agent Verifies and Aggregates #

All children succeeded. Agent tests the integrated result, confirms it works.

Agent calls: 9plan_plan_complete
  outcome: "Display layer complete. Aggregated from child plans:
           
           - x5k9m: PostList component in src/components/PostList.tsx
           - r3t7w: usePagination hook in src/hooks/usePagination.ts
           - j8n2q: Integration in src/pages/index.tsx
           
           All components working together. Posts display with functional
           pagination. Loading states and error handling in place.
           
           The blog application is now feature-complete."

Phase 7: Session Complete #

Agent calls: 9plan_queue_pull

Response:
  [Session: amber-quiet-river]
  Queue is empty. Task complete!
  
  Completed plans: 6
  Use 9plan_history_search to review outcomes.

Final State #

Queue: Empty

History: All 6 plans indexed and searchable

  • k7f3m: Ghost API Client
  • m2x9p: Cache System
  • x5k9m: PostList UI
  • r3t7w: Pagination State
  • j8n2q: Integration
  • p4r2k: Display Layer (parent/aggregator)

Files:

amber-quiet-river/
├── session.db          # All history indexed
└── plans/              # Empty - all plans completed

Key Observations #

Dependency Flow #

k7f3m (Ghost Client)
    ↓
m2x9p (Cache) ←────────────────────┐
    ↓                              │
x5k9m (PostList UI) ←── no deps    │
    ↓                              │
r3t7w (Pagination) ←── no deps     │
    ↓                              │
j8n2q (Integration) ←── needs all ─┘
    ↓
p4r2k (Aggregation) ←── verifies children

Cross-Branch Visibility #

When p4r2k was decomposed, all three children were created in the same context. This was the moment to capture that j8n2q (Integration) would need outputs from the Cache System (m2x9p), not just its sibling UI plans.

Semantic Resolution in Action #

j8n2q declared an input: "cached_client: from Cache System work"

At execution time, agent searched:

9plan_history_search("cached_client Cache System")

And found m2x9p's outcome describing exactly where to find it.

Parent Aggregation Value #

p4r2k completing last allowed:

  1. Verification that all UI pieces integrated correctly
  2. A milestone record documenting the full Display Layer
  3. A single point summarizing three child plans' work

If someone later asks "what was the Display Layer work?", searching for p4r2k gives them the complete picture without finding all three children separately.