Flownix
Sections
On this page

execute-task

Use when doing the actual work for a node tracked in Flownix — task, plan, feature or epic. Triggers on "execute AF-TASK-12", "work on this ticket", "take this task", "implement the plan", "возьми задачу", "выполни тикет", "сделай AF-TASK-1

Execute Work

Do the work for any Flownix node while keeping the ticket as the live record of truth. Slug lookups work everywhere: pass slug (+ optional project_id) instead of node_id. Prerequisite: flownix-basics. After completion, review-work handles verification and documentation.

By node kind

  • task — a self-contained unit. Implement, test, commit. TDD: failing test → implement → verify → commit.
  • plan — read its content for the approach, execute child tasks in dependency order, then mark the plan done.
  • feature — a shippable capability, possibly several plans. Execute each, verify end-to-end, then create its doc node and set_references back to it. Both calls or neither — a doc node nothing points at is a doc nobody reads.
  • epic — execute its features in order, then close.

Workflow

0. Load project context

shell
cat .flownix 2>/dev/null || cat .ai-flow

Parse the YAML for project_id. Neither file exists → run flownix-init.

1. Load context (always first)

  • get_node(slug: "ACME-TASK-1", project_id: "…") — read content (spec/acceptance criteria) and every prior comment.
  • Children: child_ids in the response; get_node each. Execute in dependency order — dependency_ids (or get_dependenciesdepends_on) lists blockers. Don't start a task whose blockers are still open.
  • Pull the surrounding knowledge the ticket doesn't repeat:
    shell
    rag_context({ project_id, query: "<task title> — prior decisions, conventions, related work" })
    rag_query({ project_id, query: "<the thing you're about to build>", k: 5 })
    Hits are leads — get_node before relying on one. On rag-service unavailable, fall back to get_tree/get_node and say so. See flownix-rag-search.

Optional, one call: session_announce({ agent_name, ai_model, host, cwd, git_branch }) puts your model and machine on the live presence panel. Skipping it costs nothing but a less informative row.

2. Claim the work — after checking the approval gate

Before moving anything into in_progress, when the project has require_proposal_approval on (get_project_policy, meaningful only with spec_mode: strict): check that no delta covering this node is waiting for review.

shell
list_doc_deltas(source_node_slug: "<this node, then its plan, then its feature>")

A delta in state: proposed whose review_status is pending or rejected blocks the start of work — and it blocks from above too: a delta proposed from the feature stops the tasks underneath it. The server refuses the transition with FailedPrecondition prefixed proposal_not_approved, but check first: reaching the refusal wastes the user's turn instead of handing them the decision.

If a covering delta is not approved: stop, name it, and ask the user to approve it (they do it in the web UI; approve_doc_delta refuses agent sessions by design). Do not re-propose it, do not delete it, do not turn the policy off. See flownix-write-spec.

shell
update_node_status(slug: "ACME-TASK-1", project_id: "…", status: "in_progress")

add_comment with [progress]: "Starting — plan of attack: …".

2b. If the gate refuses to let you create a task

In a project with spec_first on, create_node (and move_node) for a task or plan under a feature is refused with FailedPrecondition prefixed spec_first_not_approved until that feature has an approved delta. The refusal names the feature, the state of its deltas, and the calls that lift it.

The answer is to go back to the change, not around it. Read the feature's document, draft or finish its delta, submit_doc_delta, stop and ask the human to approve it — the procedure is spec-first-change. Only then cut the tasks, and cut them from the document that was approved.

None of these is a way forward, and all of them look like one:

  • creating the task under the epic or the project instead, to sidestep the feature;
  • moving it under the feature afterwards — move_node is gated identically;
  • declare_no_spec_impact on a feature that really does change described behaviour. It is available, cheap and looks legitimate, which is exactly what makes it the tempting wrong turn;
  • set_project_policy to turn the mode off. Changing the project's policy to get around the project's policy is the failure, not the workaround.

3. Check the component binding — mandatory

Before writing code, confirm the node is bound to the parts of the system it actually touches. Work that lands in no component is invisible in the system view and counted in no progress.

shell
list_components({ project_id })                                   // the system's own map
set_node_components({ node: "ACME-TASK-1", components: ["AF-COMP-3", "AF-COMP-7"] })
  • Verify it against the work you are about to do, not against what the planner guessed. If the implementation turns out to touch another service, add that component too.
  • Several components are normal. Link every part you really change.
  • No suitable component? Create itcreate_component(\{ project_id, title, repo_path, component_kind, parent \}) with the name it has in the repository, then link. Never leave the node unbound because the inventory is incomplete; never invent a component with no code behind it.
  • set_node_components replaces the set — include the existing links unless you mean to drop them.
  • Docs you create for this work are bound the same way, in the same step.
  • The project has no components at all → run map-components first.

4. Work in tracked increments

For each meaningful step: do it, then add_comment with [progress] (what you did + result) or [decision] (a non-obvious choice + why). On long work, update_node_progress (0..100) so the board is honest. Children: after each one completes, update the parent's progress.

5. Handle blockers honestly

Can't proceed → update_node_status blocked + add_comment [blocker] stating exactly what blocks you and what would unblock it.

6. Close under strict spec mode

Read spec_mode from the config. When strict, answer before any transition to done: did this work change a contract or behaviour the project documentation describes?

  • Yes → reread the affected doc, build its complete new body, run validate_spec on that body, then propose_doc_delta with this node as the source and apply_doc_delta. A delta is the whole resulting document, never a fragment or a patch.
  • Nodeclare_no_spec_impact with a sentence naming what changed and why no documented behaviour did. An explicit conclusion, not a shortcut.

The format and the whole authoring procedure live in flownix-write-spec — read it and follow it. The OpenSpec format (## Purpose / ### Requirement: with SHALL / #### Scenario: with GIVEN/WHEN/THEN) is the only accepted way to record behaviour, validate_spec checks it, and the approval gate lives there too. It is not restated here on purpose: the same block used to sit in four skills, and four copies drift.

If the project requires approval, the delta you propose at closing time is pending until a human approves it, and apply_doc_delta is refused until then — so propose it as soon as you know what changed, not in the last minute before closing.

Never edit a doc directly as a substitute for the delta ritual. A delta you decided against is discard_doc_delta (the row stays, marked discarded); delete_doc_delta is only for a row that should never have existed. An applied delta cannot be removed — propose a new one on top.

7. Finish

  • Acceptance criteria met → update_node_status testing, progress 100.
  • update_node_content with commit_hash = the git hash of the completed work.
  • ticket_ref — if an external ticket surfaces while executing (branch name, commit message, a direct mention), set it via update_node_content(ticket_ref: "PROJ-123"). Mandatory when mentioned, never invented. list_nodes(ticket_ref: …) finds siblings on the same ticket.
  • feature/epic → create the doc node and set_references back to it in the same breath, and bind the doc to its components. A [done] comment naming a doc the node doesn't reference is not done.
  • add_comment with [done]: what was implemented, where, and how to verify it.
  • update_node_content if the spec drifted from reality.

Slug examples

shell
get_node(slug: "ACME-TASK-1", project_id: "proj_abc123")
update_node_status(slug: "ACME-TASK-1", project_id: "proj_abc123", status: "in_progress")
add_comment(slug: "ACME-TASK-1", project_id: "proj_abc123", body: "[progress] Starting…")
create_node(parent_slug: "ACME-PLAN-1", project_id: "proj_abc123", kind: "task",
            title: "New task", tags: ["backend"], components: ["AF-COMP-3"])

Rules

  • Comments and content are indexed for semantic search — name the subject, use domain words, record the why. Indexing is eventually consistent; never confirm your own write with rag_query.
  • One node at a time. Discovered extra work → create a new task, don't expand scope silently.
  • Never mark done yourself if the project has a separate review step — leave it in testing.
  • A gate refusal is information, not an obstacle. proposal_not_approved means wait for a human; spec_first_not_approved means the feature's document is not accepted yet. Both are answered by doing the missing work, never by finding a call the gate does not cover.
  • Every status change carries a comment explaining it.
  • Every node and doc you touch ends up bound to at least one component.