Skip to content

Latest commit

 

History

History
105 lines (86 loc) · 5.15 KB

File metadata and controls

105 lines (86 loc) · 5.15 KB

Agent-native surface (v2.4.0)

pTask is native vocabulary for agents: an MCP server, claim/lease mechanics, provenance links, idempotent capture, and a git-diffable export.

MCP server

Two transports, one handler, 20 tools (task_next / task_list / task_add / task_show / task_done / task_dismiss / task_edit / task_claim / task_promote / task_depend / task_capture / task_search / task_digest plus approval_request / approval_list / approval_status / approval_withdraw — agents request, they never decide; see approvals.md — plus goal_list / goal_show / goal_link; task_show, task_next and task_claim carry goal_chain and goal_source per task; see goals.md):

  • streamable-HTTP at http://127.0.0.1:9501/mcp (or your PTASK_SYNC_URL), bearer-gated to a named write token. Per-request identity cannot reach rmcp tool handlers, so attribution is pinned actor=<token-name>, source=mcp. Other agents use the scoped REST API with their own named tokens.
  • stdio via pt mcp — local registration without a network hop; actor from $PTASK_ACTOR.

Registration (~/.claude.json → mcpServers):

"ptask": {
  "type": "http",
  "url": "http://127.0.0.1:9501/mcp",
  "headers": { "Authorization": "Bearer $(cat ~/.config/ptask/agent.token)" }
}

or stdio: { "type": "stdio", "command": "pt", "args": ["mcp"], "env": {"PTASK_ACTOR": "hal"} }.

Agent mechanics

task_edit applies all requested fields, labels and its attributed event in one transaction. Invalid fields or database failures while applying the edit leave the task and journal unchanged. A successful combined edit produces one task.updated event containing the requested fields. Rescoring runs after commit; a scoring failure does not roll back a successful edit.

  • task_claim — atomic todo/backlog/triage → in_progress; the check-and-set is one UPDATE, so parallel agents can't both win. Journaled task.claimed.
  • task_depend — task depends on a prerequisite (remove=true drops the edge). A task with open prerequisites cannot be closed — task_done (and pt done, the dashboard, Telegram, sync, git-webhook auto-close) all refuse with a Blocked error naming every open blocker; HTTP surfaces return 409. Chains (3 on 2 on 1) enforce strict order; fan-out (2 on 1, 3 on 1) lets 2 and 3 close in any order once 1 is done. A dismissed prerequisite counts as satisfied. task_show returns blocked_by.
  • task_promote — flips an investigation into implementation work (kind scout → ship, deliverable report → pr) on the SAME row. Promotion must never close the scout and open a ship duplicate: that is re-ticketing, not disposition, and it inflates the open count. Journaled task.promoted; refuses a terminal task so a resurrection is always a deliberate reopen.
  • task_add(discovered_from) — records a discovered_from link in task_links; mirrors HAL's spawn_task provenance pattern.
  • task_digest — deterministic session priming (recent done/dismissed, created count, ready queue). Deliberately NOT an LLM summary: the consumer is a model; structured facts beat a second model's paraphrase and can't fail closed or hallucinate.
  • pt delegate PT-N — operator-gated skeleton: prints the headless claude -p command, never spawns it. Autonomy revisited once the loop is proven (per master-plan default).

Federation (killing the parallel task stores)

Every adapter POSTs to /capture with a stable client_key — a re-send of the same key + text returns {"duplicate": true} instead of a new inbox row, which is what stops re-nag loops. severity ≥ 3 fast-lanes into a task.

# monitoring escalation → task (idempotent per escalation id)
curl -s -X POST http://127.0.0.1:9501/capture \
  -H "Authorization: Bearer $PTASK_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"text":"[monitor] disk usage above 90% on db-1",
       "source":"monitor", "severity":3,
       "client_key":"monitor:esc-1234"}'

# heartbeat attention item (no severity — goes through distill)
curl -s -X POST http://127.0.0.1:9501/capture \
  -H "Authorization: Bearer $PTASK_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"text":"PR #50 needs operator review (open 38h)",
       "source":"heartbeat", "client_key":"heartbeat:pr50-review"}'

Adapter wiring lives in the CONSUMING repos (fleet-sentry, pureMind heartbeat, nexus) — each has a named scoped token. pending.md ↔ ptask reconciliation: heartbeat items that reference a PT-N stop being re-raised (the PT task is the record); new pending.md entries flow through the capture adapter above.

Export

pt export --git writes tasks.jsonl / task_links.jsonl / task_labels.jsonl to ~/puretensor-tasks/export/ and commits in place — a greppable, diffable projection (the SQLite spine stays canonical). ptask-export.timer runs it nightly at 04:45 UTC.

Outbound webhooks (specola)

pt serve fans out journal events to PTASK_WEBHOOK_URLS (comma-separated, HMAC-signed with PTASK_WEBHOOK_SECRET — see webhooks::sign). Point one at specola's ingest to push task changes instead of having specola poll.