Flownix
Sections
On this page

spec-first-change

Use when the project has spec_first on and a change has to be worked out before any task exists — triggers on "plan a feature", "decompose this", "разбей на задачи", "заведи фичу" in a spec-first project, on the refusal spec_first_not_appro

Work a Change Spec-First

The order of work is reversed here, and that is the whole point: the document is written and accepted first, tasks are cut from it afterwards. Not "write the spec early" — the server refuses to create a task or plan under a feature whose delta is not approved.

Prerequisites: flownix-basics, flownix-write-spec. The OpenSpec format, validate_spec and the approval gate are owned by flownix-write-spec and are not repeated here: the format used to sit in five skills, and the copy people read is always the one that drifted.

Is this your skill?

shell
get_project_policy({ project_id })

spec_first: false → this skill is not yours. Use plan-feature, which is unchanged for such projects. spec_first: true → everything below, and plan-feature hands decomposition to you.

The mode only exists together with spec_mode: strict and require_proposal_approval — the server refuses to enable it otherwise. So in a spec-first project you already know two more things: a task closes only with an applied delta or a declared no-impact, and only a human approves anything.

The procedure

1. Open the change

create_node with kind feature. Its content is the proposal: why, what changes, what the boundaries are, and which alternatives you rejected and why.

Create nothing else. No plan, no tasks — the server refuses them, and reaching that refusal wastes the user's turn instead of doing the work. Bind the feature to its components right here (flownix-basics), and set ticket_ref if an external ticket was named.

2. Find the document, do not invent one

rag_query for the behaviour, then list_docs / get_node. Change the document that already covers the area. A second document about the same subject is worse than a stale one: the reader finds one of them and never learns the other exists. create_doc_node only when nothing covers it — bound to at least one component.

3. Draft the delta

propose_doc_delta, with this feature as source_node. In a spec-first project the delta is born review_status: draft.

A draft asks nobody anything. Do not tell the user their approval is pending — it is not, and you would both be waiting for each other. It is your working copy of the document until you decide it is ready.

body is the FULL new document body, exactly as flownix-write-spec requires.

4. Work it out

update_doc_delta with the full body, as many times as it takes. Format issues come back in spec_issues and do not block the edit — a draft is written in passes, and a requirement whose scenario is not written yet is a normal intermediate state. The format is enforced at submit.

Record every rejected decision as a [decision] comment on the feature, with the reason it was rejected. This is not bookkeeping: what a team threw away is more valuable than what it kept, because the next agent will otherwise propose exactly that again. The delta's round history keeps the bodies; the comments keep the reasoning.

If the human is editing the draft in the web UI at the same time, reread it (get_doc_delta) before your next update_doc_delta — you replace the body wholesale.

5. Submit, then STOP

shell
submit_doc_delta({ revision_id })

From this moment the delta is in the review queue, it holds the gates, and it can no longer be edited in place.

Then stop. Name the delta and the document, say in one or two lines what it changes, say plainly that it needs their approval in the web UI, and wait. You cannot approve it: approve_doc_delta refuses every agent session.

Do not fill the wait with adjacent work nobody asked for. "While we wait, I'll…" is how a session ends up with changes the user never reviewed and did not want.

6. When it comes back rejected

Read review_note. Fix the same delta with update_doc_delta — it returns to draft and the rejected body stays readable in the round history. Then submit_doc_delta again.

Do not propose a new delta. A new row breaks the thread: the whole point of the round history is that "what we discarded and why" reads as one story.

7. Only now, cut the tasks

review_status: approved → decompose. Plan and tasks under the feature, each task self-contained, each bound to components, each with set_references to the document.

Cut them from the accepted document, not from what you had in mind in step 1. If the document ended up describing something different from your original idea, the document wins — that is what the human approved.

8. Execute

execute-task as usual. apply_doc_delta goes together with closing the work, not before it.

When the feature changes no documented behaviour

A refactor, a rename, a dependency bump. declare_no_spec_impact on the feature unblocks decomposition, and it wants a sentence naming what changes and why no described behaviour moves.

Two things about it:

  • It does not cascade down. Each task under the feature still answers for its own spec when it closes.
  • It is not the cheap way out. It is available, quick, and looks legitimate, which is exactly why reaching for it when the change does touch described behaviour turns this whole mode into paperwork. If you cannot write that sentence honestly, the change affects the spec.

What not to do when the gate refuses you

The refusal is FailedPrecondition prefixed spec_first_not_approved. It names the feature, the state of its deltas, and the two calls that lift it. None of the following is a way around it, and each looks like progress:

  • creating the task under the epic or the project instead, to sidestep the feature;
  • moving a task under the feature afterwards — move_node is gated identically;
  • declare_no_spec_impact on a feature that does change described behaviour;
  • set_project_policy to turn spec_first off. Changing the project's policy to get around the project's policy is the failure, not the workaround. If the mode is genuinely wrong for this work, that is a conversation to have with the user, not a call to make.

Checklist

  • get_project_policy read; spec_first is actually on.
  • Feature created with the proposal in content, bound to components. Nothing else created.
  • Existing document found, not a second one invented.
  • Delta proposed from the feature; it is a draft, and the user was not told it awaits them.
  • Rejected decisions recorded as [decision] comments on the feature.
  • submit_doc_delta called, the user told what waits for them, and work stopped.
  • After a rejection: the same delta reworked, not a new one.
  • Tasks cut only after approved, and cut from the document that was approved.