Разделы
На этой странице

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.
  • bug — a defect fix standing at feature level. Execute its plans and tasks like a feature's, but there is no spec document to write for it first. A task under a bug closes by the same rule as any task in strict mode: an applied delta, or declare_no_spec_impact with a sentence naming what was fixed and why no described behaviour changed. An ordinary fix is the second case, because it brings the system back to what the spec already says.
  • 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_dependencies → depends_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

Read get_project_policy first (see flownix-basics → Project profile and process settings). In execution_order: sequential take tasks strictly in tree order: a task whose previous sibling task is not done is refused with workflow_order — do not look for a way around it; if the previous task is waiting for review, stop and tell the user.

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

In a project with profile: simple skip this step — simple projects do not map the system.

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 it — create_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.

Token discipline while loading: one get_node per node, rag_context instead of many reads, and stop exploring once you can state the plan of attack in two sentences. Large reads (logs, generated files) go through a narrow search or a sub-agent, not into your context whole.

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.
  • No → declare_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.
  • completion_flow: review → the task stays in testing: say plainly that it awaits the user's check. Only a human moves it to done; your done would be refused with workflow_review_required, and so would closing its feature or plan while a task under it is not accepted.
  • 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.
  • Files the work produced — a benchmark, a report, a log, a diagram, an export — go to the Artifactory and a real description — a file on disk goes by link (artifact_upload_url, run the returned curl, artifact_complete_upload), inline artifact_upload only for short text not on disk; put the slug (AF-ARTF-12) in the [progress]/[done] comment instead of pasting the content. The slug in text links the file to the task.
  • add_comment with [done]: what was implemented, where, and how to verify it.
  • update_node_content if the spec drifted from reality.

Delegating to sub-agents (plans, features, epics)

Executing a plan or feature is a loop over child tasks; run it as an orchestrator, not as one long context. Rules and the tier table are in flownix-basics → Working efficiently; applied here:

  1. Read once: get_node the parent and child_ids, get_dependencies for the order. Group tasks into waves — everything whose blockers are done can run together; tasks touching the same files cannot (separate worktrees, or sequence them).
  2. Assess each task before dispatch with the four signals (files, ambiguity, blast radius, verification) and pick the tier. Start from the planner's tier:* tag; if the task has none, assess and add it (add_tag, exactly one of light|standard|deep) and note it in [progress] before dispatch. The assessment you do now wins — the code may be bigger or smaller than the plan guessed. Say the choice in one line in the task's [progress] comment ("dispatch: light — 2 files, pattern exists, tests present").
  3. Brief the sub-agent by reference: the node slug (it reads the ticket itself), the files and entry points, the acceptance check, the out-of-scope line, the commit/branch convention, and "report in ≤ 8 lines: result, files, commit hash, open questions". No pasted ticket text, no history.
  4. Verify cheaply before accepting: run the task's tests, read the diff against the acceptance criteria. Only contract/data/security changes go to a separate reviewer.
  5. Escalate one tier after the same failure twice, with the failure summary; after the top tier fails, stop and mark the task blocked with a [blocker] — do not loop.
  6. The orchestrator owns the ticket: status changes, component binding, the spec-mode close gate and the [done] comment stay with you. A sub-agent that updates status or applies deltas on its own makes the board lie.

If the client cannot start sub-agents, do the assessment anyway — it tells you how to split the work into steps small enough to keep the context focused, and what to run before moving on.

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.
  • Produced files live in the Artifactory and are referred to by slug — never pasted into a comment, never left only on the local disk.
  • Every node and doc you touch ends up bound to at least one component.