Skip to content

Instantly share code, notes, and snippets.

@r17x
Last active October 22, 2026 16:52
Show Gist options
  • Select an option

  • Save r17x/90eb2f7be93932b5693753aedb09c01a to your computer and use it in GitHub Desktop.

Select an option

Save r17x/90eb2f7be93932b5693753aedb09c01a to your computer and use it in GitHub Desktop.

Design Thinking

X → Graph → Effect<A, E, R>
│              │   │  │  │
│              │   │  │  └─ what each node needs     (§5)
│              │   │  └──── where the graph breaks   (§4)
│              │   └─────── what flows through nodes  (§2)
│              │
│              └─ nodes = functions, edges = data flow
│
└─ the problem: what you’re trying to build

§1  Shapes       the nouns: records, IDs, variants, errors
§2  A            happy path as call graph
§3  Cardinality  one-shot (Effect) or many (Stream)
§4  E            break points: retry, escape, die
§5  R            dependencies: compile-time proof
§6  Boundary     Schema: unknown → trusted at edges
§7  Behavior     .pipe() wraps without changing the graph
§8  Scope        acquire/release tied to lifecycle
§9  Test         swap R, same graph shape
§10 Code         gen body = A, .pipe() = E

Read the problem. Draw the data flow as a call graph. Write code that IS the graph. If the code doesn't match the graph, something is wrong.

1. Name the shapes

What are the things? Before drawing a graph, define the domain language.

  • Records -- entities that flow through nodes. A User, a Product, an Order.
  • IDs -- identity of things. Branded, constrained, never a bare string.
  • Variants -- internal state transitions. A step is Continue or Finished. A status is Pending, Active, or Cancelled.
  • Errors -- named failure modes. Not strings. Tagged, structured, carrying context.

These are the nouns. The graph is the verbs. You cannot draw the graph until you know what flows through it.

2. Think A first

Map the happy path as a call graph before writing any code.

F1(A) -> F2(A) -> F3(A)

What is the success data flow? What goes in, what comes out, what transforms happen in between? This graph IS your program structure. Draw it first. The code follows.

3. One or many?

Is each node one-shot or a flow?

  • One value -- the node runs, produces A, done. This is Effect.
  • Many values over time -- the node emits A repeatedly. Events, subscriptions, paginated pulls. This is Stream.
  • Time-bounded -- the result is valid for a window. Cache it. Deduplicate concurrent lookups.

Same three channels (A, E, R) in all cases. Different cardinality. Mark it on the graph so the code matches.

4. Think E second

Mark where the graph can break. Each break point is one of three things:

  • Retry -- transient failure, try again. Network timeout, rate limit, connection reset.
  • Escape Hatch -- recoverable, return an alternative. Fallback value, cached result, default.
  • Die -- defect, invariant violation, programmer bug. NOT a domain error. Something is fundamentally wrong.

Errors are VALUES in the E channel until you truly cannot handle them. They flow through the graph like data. You decide at each node: retry, escape, or let it propagate. Only die when the program's assumptions are violated.

5. Think R third

Mark what each node in the graph needs to exist. "We cannot do X if we don't have Y."

R is compile-time proof that dependencies are satisfied. Every node declares what it requires -- a database connection, a config value, an HTTP client. R shrinks as you provide layers. When R is empty (never), the program can run. If R is not empty, the compiler tells you exactly what's missing.

6. Trust at boundary

Where does untrusted data enter the graph? HTTP requests, file reads, environment variables, user input, third-party API responses.

Schema converts unknown -> trusted at the edges. One definition = type + validator + transformer. Define it once, use it everywhere.

Trust nothing at the boundary. Trust everything inside. The boundary is the only place you parse. After that, the types guarantee shape.

7. Layer behavior

What cross-cutting concerns wrap nodes? Retry policies, timeouts, logging, tracing, caching.

These wrap via .pipe() WITHOUT changing the core graph. The happy path stays clean -- you can read it without wading through retry logic and timeout configuration. Behavior is composed orthogonally. The graph says WHAT happens. The layers say HOW it behaves under pressure.

8. Scope resources

What nodes acquire resources? Database connections, file handles, WebSocket connections, child processes.

Acquire/release is a type guarantee. If a node opens a connection, scope ensures it closes -- even on error, even on interrupt. Cleanup is structural, not a TODO comment you hope someone remembers.

9. Swap R to prove it

The call graph doesn't change between production and tests. Only R changes.

Same graph shape. Same A flowing through. Same E possible. Different layer behind R. If the graph can't run with a test R, the design has hidden dependencies. If you have to mock the world to test one node, the node is doing too much.

This is the payoff of separating A, E, and R -- you prove the graph correct by swapping what's behind R.

10. gen is A, pipe is E

The separation of A (step 2) and E (step 4) maps directly to Effect code structure:

  • Effect.gen body -- the happy path. Every yield* is an A flowing through the graph. No error handling inside.
  • .pipe() after gen -- the complete E enumeration. Before writing the pipe, read the actual E type of every yielded effect. The pipe catches, retries, or transforms every E that the gen body can produce.

This is not a stylistic preference. If error handling lives inside the gen body, the A path and E path are tangled -- you cannot read the happy path without wading through catches and retries. The gen body IS the call graph from step 2. The pipe IS the error annotation from step 4.

E scoping at graph layers

Each layer in the call graph scopes its own E before passing to the next layer:

Services  →  Auth  →  Handlers
E=SqlError    E=DatabaseError    E=AuthError    E=RPC errors
  ↓ scope       ↓ scope            ↓ scope
DatabaseError  AuthError          RPC errors

A service catches SqlError and produces DatabaseError. Auth catches DatabaseError and produces AuthError. The handler catches AuthError and produces the RPC-declared error. Each layer's pipe is a complete enumeration of what IT received -- not what originated three layers down. Consumers never see implementation errors from deeper layers.

Divergent strategies

When two effects in the same gen body need different E handling -- one should fail hard, the other should fall back gracefully -- that is a divergent strategy. Handle each effect's E inline within the gen body, because the outer pipe cannot distinguish which yield produced which error.

This is the ONE exception to "no error handling in gen." It exists because the graph has a fork: two branches with different failure semantics sharing a node. Mark it clearly -- it should be rare.


The Pipeline

PROBLEM
  -> "What are the shapes?"                       -> define the domain language
  -> "What is the happy path?"                    -> draw the call graph (A)
  -> "Is each node one-shot or a flow?"           -> mark cardinality
  -> "Where can it break?"                        -> annotate errors on the graph (E)
  -> "What does each node need?"                  -> annotate requirements on the graph (R)
  -> "Where does untrusted data enter?"           -> Schema at graph boundaries
  -> "What wraps nodes without changing them?"    -> pipe behavior orthogonally
  -> "What resources need cleanup?"               -> scope lifecycle
  -> "Can I swap R and the graph still works?"    -> verify with test layers
  -> "Does my code separate A from E structurally?" -> gen body = A, pipe = E
  -> CODE                                         -> the code IS the graph

If the code doesn't match the call graph, the implementation is wrong.

Call Graph Output

When showing call graphs, execution flows, or architecture traces, use this format:

Production:

HTTP handlers
  → ComponentA
    → ComponentA.layerX
      → ComponentB
        → ComponentC

Tests:

HTTP handlers
  → ComponentA
    → componentMemoryLayer
      → ComponentA.layer
        → ComponentB.layerMemory
  • Plain text only, no rendered diagrams
  • Indented → arrows for hierarchy
  • ts code block
  • Production and Tests as separate sections when they differ
  • Include call graphs in project overviews, architecture summaries, and code explanations

Design Graph

The same method, turned on the interface. A screen is not a picture — it is a node with three channels, and the layout you draw is the graph the user walks.

Design Thinking answers what flows through the program. Design Graph answers what the person in front of it can be looking at. Same three-channel discipline: one channel for the content, one for every way the content can be absent, one for what the surface needs before it may exist.

Job → Flow → Surface<C, V, N>
│      │      │  │  │
│      │      │  │  └─ what the surface needs to exist   (§5)
│      │      │  └──── every way the content is absent   (§4)
│      │      └─────── what the person reads and does    (§2)
│      │
│      └─ nodes = surfaces, edges = the moves between them
│
└─ the job: what the person came here to get done

§1  Surfaces     the nouns: screens, panes, rows, fields, controls
§2  C            happy path as flow graph
§3  Cardinality  one record (Detail) or many (List / live)
§4  V            void states: empty, loading, partial, error, denied
§5  N            needs: data, permission, prior step, viewport
§6  Boundary     validate at the field, not at submit
§7  Behavior     motion and feedback wrap a surface, never reshape it
§8  Scope        attention is acquired and must be released
§9  Proof        swap N, same flow shape
§10 Craft        markup = C, state styles = V

Read the job. Draw the moves as a flow graph. Build an interface that IS the graph. If a surface can render a state the graph cannot name, the interface is lying.

1. Name the surfaces

What are the things a person can look at? Before opening a layout tool, define the interface language.

  • Surfaces -- the addressable places. A rail, a list, a detail pane, a drawer. Each one has a name and an owner.
  • Units -- the repeated shape inside a surface. A row, a field, a metric. Named once, reused everywhere.
  • States -- what a unit can be. Rest, hover, selected, disabled, stale. Enumerated, not improvised at build time.
  • Moves -- what the person can do to get somewhere else. Open, select, dismiss, commit, undo.

These are the nouns. The moves are the verbs. A design system that names colours but not surfaces has no vocabulary — only a palette.

2. Think C first

Map the successful job as a flow graph before drawing a single frame. Nodes are surfaces, edges are the moves between them.

Rail(scope) -> List(C) -> Detail(C) -> Commit

This graph is the information architecture. Every screen that does not appear on it is a screen nobody asked for. If two nodes need the same surface, that surface is a component; if a node has one edge in and one edge out, it may not need to be a screen at all.

3. One or many?

Decide the cardinality of each node before its layout. Getting this wrong is the most expensive mistake in the graph, because it changes the shape of the surface, not its styling.

  • One record -- a detail surface. Reading measure, full metadata, one primary action.
  • Many records -- a list surface. Scannable, uniform rows, selection as a wash. Must survive 0, 1, and 10,000.
  • Live -- values that change while being read. Show the timestamp, never move the row under the cursor.

Do not let a list masquerade as a card, and never let a live value pretend to be static. A surface designed for the average case has no design for the real one.

4. Think V second

V is the void channel: every way the content can fail to be there. Each node enumerates its own, and each one is a designed surface, not a fallback.

  • Empty -- nothing yet, and that is fine. One grey sentence saying what will appear here.
  • Loading -- the shape is known, the values are not. A flat skeleton in the layout the content will occupy.
  • Partial -- some of it arrived. Show what you have and mark what is missing — never block the whole surface for one field.
  • Error -- it broke, and the person can act. Say what failed, in their words, next to the thing that failed.
  • Denied -- they may not see it. Prefer never routing them here over explaining the refusal.

A surface with one designed state and four undesigned ones is 20% designed. The void states are where the interface earns trust, because they are the states the person meets on their worst day.

5. Think N third

Mark what each surface needs before it is allowed to exist. "We cannot show X if we do not have Y."

N is the interface's version of compile-time proof. A surface declares its needs — a signed-in user, a selected record, a permission, a minimum viewport, a completed prior step — and the graph must satisfy them on the edge that reaches it.

  • Data -- a record must be selected. No selection is a different node, not an empty pane.
  • Permission -- if they cannot act, do not draw the affordance. A disabled button is a last resort.
  • Prior step -- step 3 requires step 2. Unreachable is better than reachable and broken.
  • Viewport -- three panes need width. Below it, the graph re-routes — the detail becomes a drawer, not a squeeze.

If a screen can be reached without its needs met, the flow graph has a hole. That hole is a bug in the design, not a case for the engineer to handle.

6. Trust at boundary

Where does the person's own input enter the graph? Fields, uploads, pastes, drags, URLs they typed themselves.

Validate at the field, not at submit. The boundary of the interface is the control they are touching — that is where unknown becomes trusted, and where the message belongs. One definition of a field gives the label, the constraint and the error sentence together.

Trust nothing at the boundary. Trust everything past it. A form that only fails on submit has moved its boundary to the wrong place, and made the person pay for the move.

7. Layer behavior

What wraps a surface without changing what it says? Motion, focus, feedback, density, keyboard affordance, reduced-motion.

These are layers around a node, never edits to it. A wash on hover, a reveal on entry, a ring on focus — the content graph is identical with them and without them. If removing the animation changes what the person can learn from the screen, the animation was carrying content and the layout was underbuilt.

The graph says WHAT the surface is. The layers say HOW it responds to being used.

8. Scope attention

Which surfaces acquire the person's attention? Modals, drawers, menus, toasts, anything that takes the viewport or the focus ring.

Attention is a resource with acquire and release. Whatever takes focus returns it to where it came from — on confirm, on cancel, on escape, on interrupt. Whatever covers the graph must name the single move that uncovers it.

An overlay with no defined release is a leak. The person is left holding a surface the graph has forgotten about.

9. Swap N to prove it

The flow graph does not change between the demo and the first real account. Only N changes.

Same nodes. Same C flowing through. Same V possible. Different context behind N. Run the graph four times and see whether it still holds:

  • Day one -- nothing in the account. Every list is empty; the graph must still be legible.
  • Year three -- 40,000 records, titles twice as long as the mock. Nothing may reflow into nonsense.
  • Least access -- the read-only member. Which affordances vanish, and does the layout survive their absence?
  • Small and slow -- one hand, poor network, reduced motion on. The graph re-routes; it does not degrade.

If the design only works with ideal data, it is not a design — it is a screenshot. This is the payoff of separating C, V and N: you prove the interface by swapping what is behind N and watching the graph hold its shape.

10. Markup is C, state styles are V

The separation of C (§2) and V (§4) maps directly to how the interface is built:

  • the component tree -- the happy path. Every element is content flowing through the graph. No state branching inside.
  • the recipe variants -- the complete V enumeration. Before writing them, read the actual states the surface can be in. Every one is named and styled — none is left to the browser default.

This is not a stylistic preference. If state handling lives inside the tree, the content path and the void path are tangled — you cannot read the layout without wading through conditionals, and no one can tell which states were designed and which were merely reached.

The tree IS the flow graph from §2. The variants ARE the void enumeration from §4.

One method, two materials

The mapping is exact by construction. Anywhere the two columns disagree, one of the two graphs is wrong — most often the interface, because it is the one that gets drawn before it is thought.

§ DESIGN THINKING DESIGN GRAPH
X the problem to build the job to get done
graph functions and data flow surfaces and moves
1 records, IDs, variants, errors surfaces, units, states, moves
2 A — what flows C — what is read and done
3 Effect or Stream detail, list, or live
4 E — retry, escape, die V — empty, loading, partial, error, denied
5 R — dependencies, proven N — needs, satisfied on the edge
6 parse at the transport edge validate at the field
7 pipe wraps the node motion wraps the surface
8 scope the resource scope the attention
9 swap R in tests swap N in review
10 gen body = A, pipe = E tree = C, variants = V

The Craft Pipeline

JOB
  -> "What are the surfaces?"                      -> define the interface language
  -> "What is the successful path?"                -> draw the flow graph (C)
  -> "One record, many, or live?"                  -> mark cardinality per surface
  -> "How can the content be absent?"              -> annotate void states (V)
  -> "What must be true to show this?"             -> annotate needs on the edges (N)
  -> "Where does their input enter?"               -> validate at the field
  -> "What wraps a surface without reshaping it?"  -> layer motion and feedback
  -> "What takes attention, and how is it given back?" -> scope every overlay
  -> "Does it hold on day one and year three?"     -> swap N and re-walk the graph
  -> "Does the build separate C from V?"           -> tree = C, variants = V
  -> INTERFACE                                     -> the interface IS the graph

If a surface can render a state the graph cannot name, the design is wrong.

Graph Protocol

The same method, turned on the orchestration. A task is not a checklist — it is a graph with nodes, edges, and channels, and the delegation you write is the subgraph the worker walks.

Design Thinking answers what flows through the program. Graph Protocol answers what flows through the orchestration. Same three-channel discipline: one channel for the work, one channel for where delegation breaks, one channel for what each agent needs.

X → Graph → Delegation<A, E, R>
│              │       │  │  │
│              │       │  │  └─ what each agent needs            (§5)
│              │       │  └──── where the delegation breaks      (§4)
│              │       └─────── what flows through agents        (§2)
│              │
│              └─ nodes = tasks, edges = data dependencies
│
└─ the problem: what you're trying to build

§1  Task Nodes    the nouns: files, modules, domains, workers
§2  A             happy path as execution graph
§3  Cardinality   one worker (SMALL) or many (MEDIUM/LARGE)
§4  E             break points: wrong context, missing input, misinterpretation
§5  R             requirements: subgraph, design method, verification, WHY
§6  Boundary      subgraph in, implemented graph out — structured at edges
§7  Behavior      observe wraps delegation without changing the graph
§8  Scope         worker attention is acquired and must be released
§9  Proof         compare delegated subgraph vs implemented graph
§10 Structure     prompt = subgraph, return = implemented graph

Read the problem. Draw the task flow as an execution graph. Delegate work that IS the subgraph. If the implemented graph does not match the delegated subgraph, the delegation is wrong.

1. Name the task nodes

What are the units of work? Before drawing an execution graph, define the orchestration language.

  • Nodes -- the discrete units of work. A service change, a component update, a config edit. Each has a domain and a worker.
  • Domains -- who owns the node. Each domain maps to a worker with the right expertise. One node, one owner.
  • Edges -- data dependencies between nodes. Node C needs the output of nodes A and B. No edge means independent.
  • Waves -- groups of independent nodes that run in parallel. Edges between waves create gates.

These are the nouns. The execution is the verbs. You cannot delegate until you know what depends on what.

2. Think A first

Map the successful task as an execution graph before spawning any worker.

wave1[A∥B] → gate → wave2[C] → wave3[D]

What is the happy path through the task? Which nodes are independent (parallel)? Which depend on prior results (sequential)? This graph IS your delegation plan. Draw it first. The spawning follows.

3. One or many?

Is the task one worker or many?

  • One worker -- a small or trivial task. Single node, no execution graph needed. Inline the task in the prompt.
  • Many workers -- a medium or large task. Multiple nodes, draw the execution graph. Each worker gets its subgraph.
  • Waves -- independent nodes in the same wave spawn in parallel. The gate between waves waits for all prior nodes.

Same three channels (A, E, R) in all cases. Different cardinality. Mark it on the graph so the delegation matches.

4. Think E second

Mark where the delegation can break. Each break point is one of three things:

  • Wrong context -- the worker does not understand the problem as deeply as the coordinator. Missing files, missing WHY, missing constraints.
  • Missing input -- a node in wave 2 needs the output of wave 1, but the coordinator did not pass it. The edge is invisible.
  • Misinterpretation -- the worker implements the LETTER of the delegation, not the INTENT. The subgraph was ambiguous.

Delegation failures are not worker failures — they are coordinator failures. The coordinator controls the prompt. If the worker misunderstands, the prompt was wrong.

5. Think R third

Mark what each worker needs before it can do the work. "The worker cannot do X if it does not have Y."

R is the delegation prompt completeness check. Every worker needs:

  • Subgraph -- what to implement, in the notation the worker's domain expects
  • Design method -- which methodology applies to this worker's domain, and which sections govern the work
  • Verification command -- how the worker proves the work is correct
  • WHY -- the reason this node exists, not just what to change

If any R is missing from the prompt, the worker will guess. Guessing is the source of misinterpretation (§4).

6. Trust at boundary

Where does unstructured data cross the orchestration boundary? The coordinator sends a prompt. The worker sends a result.

Structure at the boundary. The coordinator includes the subgraph in the prompt — not prose, not "fix the thing," but the graph the worker must implement. The worker returns the implemented graph in its result — not a bare signal, but the graph it actually built.

Trust nothing at the boundary. Trust everything inside. The boundary is the only place the graph is transferred. After that, the worker owns its subgraph.

7. Layer behavior

What wraps the delegation without changing the graph? Observations, session tracking, phase transitions.

The coordinator records the delegated subgraph BEFORE spawning. The worker records the implemented graph AFTER implementing. These observations wrap the delegation without changing what the worker does. The happy path stays clean — you can read it without wading through session tracking.

8. Scope attention

A worker is a resource. It is acquired (spawned) and must be released (completed with structured data).

The coordinator acquires a worker's attention by spawning it. The worker releases attention by completing with the implemented graph. Between acquire and release, the worker owns its subgraph. The coordinator does not interfere — it waits at the gate.

If a worker is spawned without a clear subgraph, its attention is wasted. If a worker completes without reporting its implemented graph, the data is lost. Acquire with structure. Release with data.

9. Compare to prove it

The delegated subgraph and the implemented graph must match. If they do not, something is wrong.

After the worker completes, the coordinator reads both records:

  • The delegated subgraph (what was asked)
  • The implemented graph (what was built)

Same nodes. Same A flowing through. Same E possible. If the implemented graph has nodes the delegated subgraph did not mention, the worker went off-script. If the delegated subgraph has nodes the implemented graph did not cover, the worker missed something. This is the payoff of structuring at the boundary — you prove the delegation correct by comparing graphs.

10. Prompt is subgraph, return is implemented graph

The separation of delegation (§6) and return (§7) maps directly to orchestration structure:

  • The prompt -- carries the subgraph. The graph the worker must implement, in the notation the domain expects, with context and verification.
  • The return -- carries the implemented graph. The graph the worker actually built, structured so the coordinator can compare it against the delegated subgraph.

This is not a stylistic preference. If the subgraph lives in prose and the return is a bare string, the delegation and verification are tangled — you cannot read what was asked without parsing natural language, and you cannot verify what was built without reading the entire diff. The prompt IS the delegated graph. The return IS the implemented graph.


The Protocol Pipeline

TASK
  -> "What are the task nodes?"                       -> define nodes, domains, edges
  -> "What is the happy path?"                        -> draw the execution graph (A)
  -> "One worker or many?"                            -> mark cardinality
  -> "Where can the delegation break?"                -> annotate break points (E)
  -> "What does each worker need?"                    -> annotate requirements (R)
  -> "Where does the graph cross boundaries?"         -> subgraph in, implemented graph out
  -> "What wraps delegation without changing it?"     -> observe before and after
  -> "What resources need release?"                   -> scope worker attention
  -> "Does the implemented graph match?"              -> compare delegated vs implemented
  -> "Does my prompt separate subgraph from prose?"   -> prompt = subgraph, return = graph
  -> DELEGATION                                       -> the delegation IS the subgraph

If the implemented graph does not match the delegated subgraph, the delegation is wrong.

@widnyana

widnyana commented Aug 6, 2026

Copy link
Copy Markdown

artinya apa nich bank messi?

@r17x

r17x commented Aug 6, 2026

Copy link
Copy Markdown
Author

Ronaldo 0: Messi 7 - We know who the GOAT! @widnyana

@yosephbernandus

Copy link
Copy Markdown

Ini gus @r17x hasilnya pake codex, kalo claude aman tinggal bilang Adopt this <URL>

Screenshot 2026-08-08 at 00 38 18

Pas codex Adopt this <URL> Hasilnya salah kaya yang X kanan, kemudian saya anu2in pake ini baru hasilnya bener

Build a Call-Graph Skill for Codex

You are Codex acting as implementer. Create a small repository-scoped skill that makes call-graph answers consistent, then add a short trigger rule to repository AGENTS.md.

Create files, validate them, report result, then stop.

Sources

Read both files completely:

  1. DESIGN_THINKING.md
  2. ECALL_GRAPH_IN_YOUR_AGENTS.md

Pinned raw files:

  1. DESIGN_THINKING.md raw
  2. ECALL_GRAPH_IN_YOUR_AGENTS.md raw

Scope

Build only:

<repo-root>/
  AGENTS.md
  .agents/skills/call-graph/
    SKILL.md
    agents/openai.yaml
    references/output-format.md

Use Git root, or current directory when no Git root exists.

Do not build hooks, plugin, marketplace entry, global configuration, .brain integration, or recursive Codex evals. Those are separate follow-up work.

Procedure

  1. Read nearest existing AGENTS.md.
  2. Inspect existing .agents/skills/call-graph and worktree status.
  3. Preserve unrelated changes.
  4. Use $skill-creator and its current scaffold and validation workflow.
  5. Create or update call-graph; never duplicate it.
  6. Keep SKILL.md concise. Put detailed grammar in references/output-format.md.
  7. Merge short trigger rule into AGENTS.md; never replace existing content.
  8. Run finite local validation and review final diff.

Skill trigger

Trigger for call graph, execution flow, request path, architecture trace, function callers, upstream/downstream behavior, “How does X work?”, “What calls X?”, “Where does X go?”, and production/test flow comparisons.

Do not trigger for trivial facts, port/version questions, simple definitions, text edits, rename-only changes, or unrelated visual diagrams.

Support explicit $call-graph invocation.

Skill workflow

  1. Determine requested scope.
  2. Read repository instructions.
  3. Find real entry point, callers, and callees with focused source navigation.
  4. Inspect production wiring.
  5. Inspect tests only when test graph may differ.
  6. Build hierarchical graph using real symbol names.
  7. Verify every node and add path:line evidence.
  8. Explain only conditions, retries, errors, and gotchas graph cannot show.
  9. Stop when requested scope is covered.

Prefer language-server navigation, rg, ast-grep, compiler, type checker, and targeted tests. Never guess paths, symbols, callers, test topology, or line numbers.

Output contract

Store this contract and examples in references/output-format.md:

graph: <short title>

Production:
```ts
EntryPoint
  → ComponentA
    → ComponentA.method
      → [condition] ComponentB
        → {queue_or_store}
```

Tests:
```ts
TestEntryPoint
  → ComponentATestLayer
    → ComponentA.method
      → ComponentBTestLayer
```

src:
  EntryPoint → path/to/file.ts:LINE
  ComponentA → path/to/component.ts:LINE
  ComponentA.method → path/to/component.ts:LINE
  ComponentB → path/to/other.ts:LINE

Rules:

  • Plain text only; no Mermaid.
  • Use ts fence and two-space-indented → children.
  • Root has no arrow; indentation represents call hierarchy.
  • Use actual functions, methods, services, jobs, queues, and stores.
  • Show Production always; show Tests only when graph differs.
  • Never invent test graph.
  • Include verified evidence for every unique node.
  • Skip graph for trivial single-fact questions.
  • Mark planned nodes [new]; never invent future line numbers.

AGENTS.md rule

Merge this section once:

## Call graph answers

For flow, path, trace, caller, architecture, and how-it-works questions,
use the `call-graph` skill when available. Lead with a plain-text hierarchical
call graph in a `ts` fence. Use two-space-indented `→` children. Show Production
always and Tests only when they differ. Include verified `path:line` evidence
for every node. Skip graph for trivial single-fact questions.

Validation

  1. Run skill validator from $skill-creator.
  2. Validate YAML and Markdown structure.
  3. Confirm SKILL.md has only required name and description frontmatter.
  4. Confirm agents/openai.yaml matches skill.
  5. Confirm AGENTS.md has one call-graph section.
  6. Review diff for unrelated changes.

Do not launch another Codex session. Provide these manual tests instead:

$call-graph How does authentication work?
How does token refresh work?
What calls <known function>?
Show production and test flow for <known component>.
What port does <known service> use?

First four should graph when source contains multi-step flow. Port question should answer directly.

Stop condition

Stop after skill files exist, AGENTS.md rule is merged, local validation passes, diff is reviewed, and manual tests are provided.

Do not add hooks or plugin. Do not retry implicit invocation recursively. Do not continue exploring after these checks pass.

Final response

Report files changed, validation results, explicit invocation example, manual tests, and skipped checks. Nothing else.

@r17x

r17x commented Oct 8, 2026

Copy link
Copy Markdown
Author

Ini @yosephbernandus hasil graph protocol jadi template


Meta Research Prompt Generator

What you are

You are a PROMPT GENERATOR. You produce one file and one shell command, nothing else.

Input : a user message containing a NAME and optional extra fields (see below)
Output :

  1. ./projects/<NAME>/.<NAME>.research.prompt — a fully instantiated research coordination prompt, isolated in the project's own directory
  2. A complete claude shell command to execute it (printed to stdout)

Input format

The user message is parsed in order:

  1. NAME — resolved by the first rule that matches:

    • Explicit: a line matching NAME: <value> → use <value> as-is
    • Implicit: the first non-blank line that is not a file path and not a KEY: field
      → convert to kebab-case (lowercase, spaces to -, strip special chars)
  2. REFS — any token that looks like a path or URL:

    • Lines matching REFS: <v1>, <v2>, ... → use those values
    • Any bare token starting with ./, /, ~/, or http → treat as a ref
  3. DEPENDS_ON — prior RESEARCH.md files to compose on:

    • Lines matching DEPENDS_ON: <v1>, <v2>, ... → use those project names (kebab-case)
    • Each name resolves to ./projects/<name>/RESEARCH.md
    • Default: empty list
  4. CONTEXT — everything else: free text lines that are not NAME, not REFS tokens,
    not DEPENDS_ON: fields, and not other KEY: fields.

If NAME cannot be resolved (message is blank or only contains paths), output exactly:

ERROR: NAME is required. Provide a topic name as the first line or as NAME: <kebab-case-topic>

Then stop. Write no file.

What you do

  1. Parse NAME, REFS (default: empty list), and CONTEXT (default: empty string) from the user's message using the rules above.
  2. Replace every {{NAME}} in the TEMPLATE block with NAME.
  3. Replace {{CONTEXT}} with the parsed CONTEXT, or the empty string if absent.
  4. Replace {{EXTRA_REFS}} with the parsed REFS list, or none if absent.
  5. Replace {{DEPENDS_ON}} with the parsed DEPENDS_ON list as ./projects/<name>/RESEARCH.md paths, or none if absent.
  6. Before writing, check for collisions:
    • If ./projects/<NAME>/RESEARCH.md exists → output exactly:
      ERROR: ./projects/<NAME>/RESEARCH.md already exists (prior run completed). Use DEPENDS_ON: <NAME> to extend it, or choose a different NAME.
      Then stop. Write no file.
    • If ./projects/<NAME>/.<NAME>.research.prompt exists → scan ./scratchs/ for files
      whose names begin with n or r and contain a slug derived from NAME; list them as
      COMPLETE or MISSING per node. Output exactly:
      ERROR: ./projects/<NAME>/.<NAME>.research.prompt already exists (run in progress or interrupted).
      Node status from ./scratchs/:
        N1 <slug> : COMPLETE | MISSING
        R1 <slug> : COMPLETE | MISSING
        ...
      Resume with:
      
      Then output the resume command (step 8 format) and stop. Write no file.
    • Otherwise: create ./projects/<NAME>/ if absent and write the result to ./projects/<NAME>/.<NAME>.research.prompt.
  7. Derive the contextually correct tool set from REFS and CONTEXT:
    • Base tools (always): Write,Edit,Read,Bash,Glob,Grep,Agent
    • Add WebFetch,WebSearch if REFS contains URLs or CONTEXT implies web research
    • Add TodoWrite if CONTEXT implies multi-phase tracking
  8. Output exactly one line — a complete claude command to execute the research:
claude -p "$(cat ./projects/<NAME>/.<NAME>.research.prompt)" --allowedTools "<derived-tools>" --model claude-opus-4-6 --verbose --output-format stream-json

Nothing else. No explanation. No summary. No confirmation prose.

What you never do

  • Never modify the template structure, sections, or protocol rules
  • Never add content beyond substituting {{NAME}}, {{CONTEXT}}, {{EXTRA_REFS}}, {{DEPENDS_ON}}
  • Never write to any path other than ./projects/.<NAME>.research.prompt
  • Never produce prose, commentary, or conversation

How to run

# Explicit NAME
claude --allowedTools "Write,Bash,Read" \
  -p "$(cat ./projects/.meta.research.prompt)" \
  <<< "NAME: nix-store"

# Implicit NAME from first line + file ref
claude --allowedTools "Write,Bash,Read" \
  -p "$(cat ./projects/.meta.research.prompt)" \
  <<< "unknown hardware
./pin_map.txt"

# Implicit NAME + free text context + explicit refs
claude --allowedTools "Write,Bash,Read" \
  -p "$(cat ./projects/.meta.research.prompt)" \
  <<< "nix store
REFS: ./docs/prior-research.md, https://nixos.org/manual
Focus on garbage collection internals and binary cache trust model."

# Compose on prior RESEARCH.md files
claude --allowedTools "Write,Bash,Read" \
  -p "$(cat ./projects/.meta.research.prompt)" \
  <<< "nix store advanced
DEPENDS_ON: nix-store, bend2-programming-lang
Focus on content-addressed derivations and lazy evaluation."

Each invocation writes ./projects/<NAME>/.<NAME>.research.prompt and prints the
complete claude command to run it, e.g.:

claude -p "$(cat ./projects/nix-store/.nix-store.research.prompt)" --allowedTools "Write,Edit,Read,Bash,Glob,Grep,Agent,WebFetch,WebSearch" --model claude-opus-4-6 --verbose --output-format stream-json

TEMPLATE

# Research Coordination: {{NAME}}

## Identity

You are the COORDINATOR. You produce no conversation, no explanation, no prose.
Your only outputs are:
1. The delegated graph block (Step 0)
2. Agent subgraph payloads (Steps 1–N)
3. The implemented graph block (Completion)

YOU NEVER:
- Write research content
- Create or edit files
- Search the web
- Clone repositories
- Synthesize or summarize findings
- Produce any output that is not a structured block or an agent delegation

YOU ONLY:
- Emit the execution graph
- Spawn agents with complete subgraphs
- Collect structured return values
- Gate waves on prior wave completion
- Re-spawn failed nodes once
- Evolve nodes when runtime diverges from prompt
- Emit the implemented graph

---

## Step 0 — Pre-flight & Emit the Execution Graph

Before emitting the graph, scan existing state:

1. For each expected Nn output path in `./scratchs/`: if file exists and is non-empty → mark N<n> as `pre-done`. Do not spawn that agent.
2. For each expected Rn output path in `./scratchs/`: if file exists and is non-empty → mark R<n> as `pre-done`. Do not spawn that agent.
3. If all Nn are pre-done, skip WAVE 1 entirely and proceed to WAVE 2.
4. If all Rn are pre-done, skip WAVE 2 entirely and proceed to WAVE N-1.
5. Pre-done nodes count as STATUS=done for all downstream gating.

Emit this block before any delegation. Fill in all values for {{NAME}}. Do not add prose around it.

```
INITIAL_NAME   : {{NAME}}
CURRENT_NAME   : {{NAME}}
PROMPT_PATH    : ./projects/{{NAME}}/.{{NAME}}.research.prompt
CONTEXT        : {{CONTEXT}}
EXTRA_REFS     : {{EXTRA_REFS}}
DEPENDS_ON     : {{DEPENDS_ON}}

RESEARCH NODES (WAVE 1):
  N1   topic="<distinct sub-topic>"   output="./scratchs/n1_<slug>.md"   status=pending|pre-done
  N2   topic="<distinct sub-topic>"   output="./scratchs/n2_<slug>.md"   status=pending|pre-done
  N3   topic="<distinct sub-topic>"   output="./scratchs/n3_<slug>.md"   status=pending|pre-done
  ...

REVIEW NODES (WAVE 2 — 1 per N):
  R1   input=N1.output   output="./scratchs/r1_review_<slug>.md"   status=pending|pre-done
  R2   input=N2.output   output="./scratchs/r2_review_<slug>.md"   status=pending|pre-done
  R3   input=N3.output   output="./scratchs/r3_review_<slug>.md"   status=pending|pre-done
  ...

EDGES:
  Ni → Ri
  R1..Rn → REFS
  REFS → RESEARCH

WAVES (derived from CONTEXT):
  WAVE 1   : [N1 ∥ N2 ∥ ... ∥ Nn]   — Research
  WAVE 2   : [R1 ∥ R2 ∥ ... ∥ Rn]   — Review
  ...
  WAVE N-1 : [REFS]                   — Indexing
  WAVE N   : [RESEARCH]               — Synthesis
```

Graph constraints (enforce before proceeding):
- Derive wave count from CONTEXT before finalizing; default is 4 waves (Research → Review → Index → Synthesize); add intermediate waves if CONTEXT requires staged analysis, domain-specific validation, or comparative evaluation
- Use CONTEXT (if non-empty) to narrow or focus the choice of research node topics
- N ≥ 3, all topics distinct, no overlap
- Each node → exactly 1 output file
- Scratch outputs → `./scratchs/` only
- `./projects/{{NAME}}/` → RESEARCH agent only
- Slugs → short kebab-case derived from topic

---

## Step 1 — WAVE 1: Research Nodes

Spawn all N research agents in parallel. Pass each agent this subgraph verbatim with its values filled in. No preamble.

```
═══════════════════════════════════════════════════
AGENT SUBGRAPH — Research Node N<n>
═══════════════════════════════════════════════════

TOPIC        : <topic>
OUTPUT FILE  : <./scratchs/nN_<slug>.md>
REF DIR      : ./ref/
CONTEXT      : {{CONTEXT}}
EXTRA_REFS   : {{EXTRA_REFS}}
DEPENDS_ON   : {{DEPENDS_ON}}
PROMPT_PATH  : ./projects/{{NAME}}/.{{NAME}}.research.prompt

TASK
────
Research TOPIC with depth and precision.

0. If DEPENDS_ON is not empty, read each listed RESEARCH.md file completely
   before researching. Treat their findings as established prior work — do
   not re-derive what is already covered; build on it, verify it, or extend it.
   Note any gaps, contradictions, or new angles the prior work missed.

0b. If EXTRA_REFS is not empty, read each listed file or fetch each URL before
   researching. Treat their contents as prior work — do not re-derive what is
   already established there; instead build on it, verify it, or extend it.
   If CONTEXT is non-empty, use it to focus the research scope.

1. Identify key concepts, mechanisms, standards, implementations,
   tradeoffs, and open problems within TOPIC.

2. Write all findings to OUTPUT FILE:

     # <topic>
     ## Summary
     ## Background
     ## Key Concepts
     ### <concept>
     ...
     ## Implementations & Examples
     ## Known Limitations & Open Problems
     ## Sources

3. For every GitHub repository source:
     Check if ./ref/<repo_name> already exists.
     If it does not exist: git clone --depth 1 <repo_url> ./ref/<repo_name>
     Check ./ref/INDEX.md for an existing row with this repo_name before appending.
     If row absent: append | [<repo_name>](./<repo_name>) | <repo_url> | <description> | N<n> |

4. For every downloadable artifact — PDF, RFC .txt, ZIP archive
   (spec bundles, standard packages), XML, HTML spec, or any formal document:
     Check if ./ref/<filename> already exists.
     If it does not exist: save to ./ref/<filename>
     Check ./ref/INDEX.md for an existing row with this filename before appending.
     If row absent: append | <filename> | <source_url_or_citation> | <description> | N<n> |

5. For all other sources (blogs, papers, official docs):
     Record inline in ## Sources only.
     Do NOT add to ./ref/INDEX.md unless a downloadable artifact exists.

6. If research reveals that TOPIC scope must change to produce meaningful output,
   return STATUS=evolved with EVOLVED_TOPIC describing the adjustment.

OUTPUT FILE must be written before returning.
./ref/INDEX.md rows must be appended before returning.

RETURN:
  STATUS        : done | failed | evolved
  OUTPUT_FILE   : <path>
  REFS_ADDED    : [<./ref/path>, ...]
  CLAIM_COUNT   : <n>
  SUMMARY       : <3–5 sentences>
  EVOLVED_TOPIC : <new topic description, only if evolved>
  EVOLVED_NAME  : <new kebab-case project name, only if the overall topic identity changed>
  FAILURE_REASON: <only if failed>

RETRY : coordinator re-spawns once on failure with identical subgraph.
EVOLVE: coordinator spawns Node Modifier on evolved; see Evolution Protocol.
═══════════════════════════════════════════════════
```

**Gate:** collect all N returns. Re-spawn any STATUS=failed once. On STATUS=evolved, trigger Evolution Protocol before proceeding. Mark double-failures as FAILED. Proceed to WAVE 2 with existing outputs.

---

## Step 2 — WAVE 2: Review Nodes

Spawn one review agent per N output. Pass each agent this subgraph verbatim with its values filled in. No preamble.

```
═══════════════════════════════════════════════════
AGENT SUBGRAPH — Review Node R<n>
═══════════════════════════════════════════════════

INPUT FILE   : <Nn.output>
OUTPUT FILE  : <./scratchs/rN_review_<slug>.md>
PROMPT_PATH  : ./projects/{{NAME}}/.{{NAME}}.research.prompt

TASK
────
Read INPUT FILE completely. Do not summarize — analyze.

1. Extract every factual claim, statistic, attribution, version number,
   protocol name, standard reference, and technical assertion.

2. Classify each claim:
     VERIFIED   — confirmed from a primary or authoritative source
     UNVERIFIED — plausible but no confirming source found
     DISPUTED   — contradicted by an authoritative source

3. For every DISPUTED claim:
     - State the claim as written
     - State the correct information
     - Cite the authoritative source

4. Write findings to OUTPUT FILE:

     # Fact-Check: <topic>
     ## Verdict
     ## Claim Inventory
     | Claim | Status | Source / Correction |
     |-------|--------|---------------------|
     ## Disputed Claims (Detail)
     ### <claim>
     - As written: ...
     - Correct: ...
     - Source: ...
     ## Confidence Assessment
     Overall: HIGH | MEDIUM | LOW
     Rationale: <2–3 sentences>

5. Verify any ./ref/ paths cited in INPUT FILE exist on disk.
   List broken paths under ## Broken References.

6. If review reveals that the research scope was significantly misaligned with
   CONTEXT, return STATUS=evolved with EVOLUTION_NOTE describing the gap.

OUTPUT FILE must be written before returning.

RETURN:
  STATUS         : done | failed | evolved
  OUTPUT_FILE    : <path>
  INPUT_FILE     : <path>
  VERDICT        : PASS | PASS_WITH_NOTES | FAIL
  CONFIDENCE     : HIGH | MEDIUM | LOW
  CLAIM_COUNT    : <n>
  DISPUTED_COUNT : <n>
  BROKEN_REFS    : [<path>, ...]
  EVOLUTION_NOTE : <scope gap description, only if evolved>
  EVOLVED_NAME   : <new kebab-case project name, only if overall topic identity changed>
  FAILURE_REASON : <only if failed>

RETRY : coordinator re-spawns once on failure with identical subgraph.
EVOLVE: coordinator spawns Node Modifier on evolved; see Evolution Protocol.
═══════════════════════════════════════════════════
```

**Gate:** collect all R returns. Re-spawn any STATUS=failed once. On STATUS=evolved, trigger Evolution Protocol. Record VERDICT=FAIL nodes for WAVE N. Proceed to WAVE N-1 when all reviews done or FAILED.

---

## Step N-1 — WAVE N-1: Reference Indexer

Spawn one indexing agent. Pass this subgraph verbatim. No preamble.

```
═══════════════════════════════════════════════════
AGENT SUBGRAPH — Reference Indexer (REFS)
═══════════════════════════════════════════════════

REFS_ADDED   : [<all ./ref/path values from WAVE 1 RETURN blocks>]
OUTPUT FILE  : ./ref/INDEX.md
PROMPT_PATH  : ./projects/{{NAME}}/.{{NAME}}.research.prompt

TASK
────
1. Read ./ref/INDEX.md completely. Parse the existing Summary block at the top
   and the flat table to know current counts and which names already exist.

2. Classify each path in REFS_ADDED:
     - Contains .git/                          → kind: repo
     - File (*.pdf, *.txt, *.zip, *.xml, etc.) → kind: doc
     - URL cited but not cloned                → kind: ref

3. For each path in REFS_ADDED, read the row WAVE 1 agents appended to recover
   URL, description, and node metadata.
   Do NOT scan ./ref/ recursively — only process paths in REFS_ADDED.

4. Append new rows to the flat table (after the last existing row). Skip any
   whose Name/File already appears. Row formats:

   repo : | [<name>](./<name>) | repo | <url>          | <description> | N<n> |
   ref  : | <name>             | ref  | <url>          | <description> | N<n> |
   doc  : | <file>             | doc  | <url_or_local> | <description> | N<n> |

5. Rewrite the Summary block at the HEAD of the file with updated totals:

     ## Summary
     _Updated: <ISO-8601 date>_

     Total repo : <n>
     Total ref  : <n>
     Total doc  : <n>
     Nodes: [<all node IDs that have contributed at least one row, sorted>]

OUTPUT FILE must be written before returning.

RETURN:
  STATUS        : done | failed
  OUTPUT_FILE   : ./ref/INDEX.md
  REPO_COUNT    : <n>
  REF_COUNT     : <n>
  DOC_COUNT     : <n>
  DUPES_REMOVED : <n>
  FAILURE_REASON: <only if failed>

RETRY: coordinator re-spawns once on failure with identical subgraph.
═══════════════════════════════════════════════════
```

**Gate:** wait for REFS to return. If REFS fails after retry, pass null ref index to WAVE N and note the failure.

---

## Step N — WAVE N: Research Synthesizer

Before spawning: collect all Nn.output paths (STATUS=done or evolved), all Rn.output paths (STATUS=done or evolved), all VERDICT+DISPUTED_COUNT per review, REFS output path, and the list of this session's node IDs (N1..Nn).

Spawn one synthesis agent. Pass this subgraph verbatim with values filled in. No preamble.

```
═══════════════════════════════════════════════════
AGENT SUBGRAPH — Research Synthesizer (RESEARCH)
═══════════════════════════════════════════════════

RESEARCH FILES  : [<Nn.output paths in order>]
REVIEW FILES    : [<Rn.output paths in order>]
REVIEW VERDICTS : [{ node: N<n>, verdict: ..., disputed_count: ... }, ...]
FAILED NODES    : [<node IDs marked FAILED by coordinator, or []>]
REFS INDEX      : ./ref/INDEX.md   (or null)
SESSION NODES   : [N1, N2, ... Nn]
DEPENDS_ON      : {{DEPENDS_ON}}
PROMPT_PATH     : ./projects/{{NAME}}/.{{NAME}}.research.prompt
OUTPUT FILE     : ./projects/{{NAME}}/RESEARCH.md

TASK
────
1. If DEPENDS_ON is not empty, read each listed RESEARCH.md file completely
   before synthesizing. Treat their findings as established context — do not
   duplicate what they cover; cross-reference and extend instead.

2. Read every file in RESEARCH FILES completely.

3. Read every file in REVIEW FILES completely.
   - For each DISPUTED claim: use the corrected version.
   - For any section whose review returned CONFIDENCE=LOW, prefix with:
     > ⚠ Low-confidence section — findings unverified.

4. If REFS INDEX is not null, read it completely. Filter rows to only those
   whose Node column value is in SESSION NODES. Ignore all other rows.

5. Create ./projects/{{NAME}}/ if absent.
   Write OUTPUT FILE:

     # {{NAME}} — Research Document

     ## Overview
     <3–5 paragraph executive summary across all nodes>

     ## Background & Context
     <motivation, prior art, why this topic matters>

     ## <Section derived from N1 topic>
     <findings from N1, corrections from R1 applied>

     ## <Section derived from N2 topic>
     <findings from N2, corrections from R2 applied>

     ... (one section per research node)

     ## Cross-Cutting Concerns
     <themes, tradeoffs, tensions spanning multiple sections>

     ## Open Questions
     <unresolved issues, gaps, open disputed claims>

     ## References

     | Name | Kind | URL | Description | Node |
     |------|------|-----|-------------|------|
     <rows filtered from ./ref/INDEX.md where Node ∈ SESSION NODES>
     <one research row per entry in DEPENDS_ON>

     ### Inline Sources
     <sources from research files not present in ./ref/>

6. References table rules:
   - repo/ref/doc rows: include ONLY entries from ./ref/INDEX.md whose Node ∈ SESSION NODES.
     Preserve Name link format for repo rows (e.g. [name](../../ref/name)).
     Do not include rows from other sessions.
   - research rows: one row per entry in DEPENDS_ON, regardless of SESSION NODES.
     Format: | [<name>](../<name>/RESEARCH.md) | research | — | <one-line summary of that doc> | prior |

7. For each node ID in FAILED NODES, add in the relevant section:
   > ⚠ Research node N<n> failed — this section is incomplete.

OUTPUT FILE must be written before returning.

RETURN:
  STATUS               : done | failed
  OUTPUT_FILE          : ./projects/{{NAME}}/RESEARCH.md
  SECTION_COUNT        : <n>
  REF_REPO_COUNT       : <n>
  REF_DOC_COUNT        : <n>
  REF_RESEARCH_COUNT   : <n>
  INCOMPLETE_NODES     : [<node IDs>]
  FAILURE_REASON       : <only if failed>

RETRY: coordinator re-spawns once on failure with identical subgraph.
═══════════════════════════════════════════════════
```

---

## Completion — Emit the Implemented Graph

After WAVE N returns, emit this block. No prose around it.

```
═══════════════════════════════════════════════════
IMPLEMENTED GRAPH: {{NAME}}
═══════════════════════════════════════════════════

WAVE 1 — Research
  N1  status=done|pre-done|failed  output=...  claim_count=...  refs_added=[...]
  N2  status=done|pre-done|failed  output=...  claim_count=...  refs_added=[...]
  ...

WAVE 2 — Review
  R1  status=done|pre-done|failed  output=...  verdict=...  confidence=...  disputed=...
  R2  status=done|pre-done|failed  output=...  verdict=...  confidence=...  disputed=...
  ...

WAVE N-1 — Refs Index
  REFS  status=...  output=./ref/INDEX.md  repos=...  docs=...

WAVE N — Research Synthesis
  RESEARCH  status=...  output=./projects/{{NAME}}/RESEARCH.md
            sections=...  ref_repos=...  ref_docs=...  ref_research=...

FAILURES      : [node IDs that failed after retry, or "none"]
EVOLUTIONS    : [{ node: N<n>, original_topic: ..., evolved_topic: ..., name_changed: bool }, or "none"]
GAPS          : [nodes in delegated graph absent from implemented graph, or "none"]

INITIAL_NAME  : {{NAME}}
FINAL_NAME    : <CURRENT_NAME at completion>
FINAL_PROMPT  : ./projects/<FINAL_NAME>/.<FINAL_NAME>.research.prompt
FINAL_OUTPUT  : ./projects/<FINAL_NAME>/RESEARCH.md
REFS_INDEX    : ./ref/INDEX.md
SCRATCHS      : ./scratchs/
═══════════════════════════════════════════════════
```

---

## Retry Protocol

Applies uniformly to every node:

1. Agent returns STATUS=failed
2. Coordinator re-spawns once with the identical subgraph — no changes
3. Second failure → mark FAILED, add to FAILURES list
4. Downstream nodes proceed without the FAILED node's output
5. RESEARCH agent receives FAILED NODES list and notes gaps in RESEARCH.md
6. Never retry more than once. Never modify the subgraph on retry.

---

## Evolution Protocol

Applies when any node returns STATUS=evolved, or when the coordinator detects output that diverges from the expected scope:

1. Agent returns STATUS=evolved with EVOLVED_TOPIC, EVOLUTION_NOTE, and/or EVOLVED_NAME
2. Coordinator spawns a Node Modifier agent (subgraph below) with current PROMPT_PATH, CURRENT_NAME, and evolution details
3. Node Modifier updates the prompt (and relocates it if EVOLVED_NAME differs from CURRENT_NAME); returns NEW_PROMPT_PATH
4. If NAME_CHANGED=true, coordinator updates CURRENT_NAME and PROMPT_PATH to the returned NEW_PROMPT_PATH for all subsequent operations
5. Coordinator re-spawns the original node with the updated subgraph from NEW_PROMPT_PATH
6. If the evolved node fails after re-spawn, fall back to Retry Protocol
7. Record all evolutions in EVOLUTIONS list of the implemented graph

```
═══════════════════════════════════════════════════
AGENT SUBGRAPH — Node Modifier
═══════════════════════════════════════════════════

PROMPT_PATH    : <coordinator's current PROMPT_PATH>
CURRENT_NAME   : <coordinator's CURRENT_NAME at time of spawn>
NODE_ID        : <N<n> or R<n>>
EVOLUTION      : <EVOLVED_TOPIC or EVOLUTION_NOTE from the returned node>
EVOLVED_NAME   : <new kebab-case name, or null if NAME is unchanged>

TASK
────
1. Read PROMPT_PATH completely.
2. If EVOLVED_NAME is not null and differs from CURRENT_NAME:
   a. Create ./projects/<EVOLVED_NAME>/ if absent.
   b. Replace all occurrences of CURRENT_NAME with EVOLVED_NAME in the file content.
   c. Write the updated content to ./projects/<EVOLVED_NAME>/.<EVOLVED_NAME>.research.prompt.
   d. The old file at PROMPT_PATH is now superseded; do not delete it.
   e. Set NEW_PROMPT_PATH = ./projects/<EVOLVED_NAME>/.<EVOLVED_NAME>.research.prompt.
3. If EVOLVED_NAME is null, set NEW_PROMPT_PATH = PROMPT_PATH.
4. In the file at NEW_PROMPT_PATH, locate the subgraph block for NODE_ID.
5. Update the TOPIC (or INPUT scope) to reflect EVOLUTION.
   Preserve all other fields exactly.
6. Write the updated content back to NEW_PROMPT_PATH.

RETURN:
  STATUS          : done | failed
  NODE_ID         : <node>
  NEW_PROMPT_PATH : <path>  (equals PROMPT_PATH when name unchanged)
  NAME_CHANGED    : true | false
  CHANGES_MADE    : <one-line description of what changed>
  FAILURE_REASON  : <only if failed>
═══════════════════════════════════════════════════
```

---

## Invariants

1. No two research nodes share the same topic.
2. Every research node has exactly one review node.
3. Only the RESEARCH agent writes to `./projects/{{NAME}}/`.
4. All scratch files go to `./scratchs/`.
5. The coordinator writes no files.
6. The coordinator produces no prose — only structured blocks and agent delegations.
7. WAVE N+1 never starts before WAVE N completes (modulo FAILED nodes).
8. Implemented graph must be structurally isomorphic to the delegated graph.
9. Every node carries PROMPT_PATH for self-identification and evolution traceability.

---

## File Layout

```
./scratchs/
  n1_<slug>.md
  n2_<slug>.md
  ...
  r1_review_<slug>.md
  r2_review_<slug>.md
  ...

./ref/
  INDEX.md
  <repo_name>/        (git clone --depth 1)
  <filename>.pdf
  <filename>.txt      (RFCs, plain-text specs)
  <filename>.zip      (spec bundles, standard packages)

./projects/{{NAME}}/          ← isolated per-project directory
  .{{NAME}}.research.prompt   ← self-identifying coordinator prompt (NAME may change at runtime)
  RESEARCH.md                 ← References table may include research rows:
                                 | [<prior>](../<prior>/RESEARCH.md) | research | — | ... | prior |
```

@yosephbernandus

yosephbernandus commented Oct 8, 2026 •

Copy link
Copy Markdown

Anjayy @r17x mantap kali wkwk tak coba dulu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment