core / project_advancer.py

Single autoadvance tick for long-running projects. Classifies the next task, runs one constrained step, and bookkeeps budget / runtime / contradictions.

API

FunctionPurpose
classify_task(description) -> "needs_user" | "coding" | "research"Keyword-driven classifier (line 85).
async advance_once(context, project_id, tool_runner, llm_classifier) -> AdvanceResultOne full advancement tick — returns the result of running one task (line 126).
project_dream_pass(store, llm_summarize)Consolidate accumulated project events into a daily digest (line 314).

Classification keywords

Tick flow

  1. Load project plan; find next READY/PENDING leaf.
  2. Classify task type.
  3. Mark IN_PROGRESS.
  4. If needs_user: flip to NEEDS_USER, log event, return.
  5. Pick tool: coding → execute, research → web_search.
  6. Run tool through the injected runner.
  7. Store result as a project artifact.
  8. Check human-gate postconditions (project_safety) → flip to NEEDS_USER if any fire.
  9. Detect contradictions with DONE siblings.
  10. Mark DONE; increment steps_used; record runtime + tool_calls.

Budget enforcement

_get_budget() reads steps_cap / steps_used from project metadata; _increment_budget() bumps after each tick. Checked via check_budget() across steps, runtime_seconds, and tool_calls.

AdvanceResult

AdvanceResult(ok: bool, task_id: str, classification: str, summary: str, artifact_id: Optional[str])

Async; tool_runner and llm_classifier are optional callbacks so the advancer can be tested without a real agent.