pi-task-orientation
Continuous task orientation for weak models: gated plan() turns the user's message, visible skills, and AGENTS.md rules into todo items; task_todo() keeps the list live with centralized status rules; turn-end checkpoints re-orient mid-task; the next user
Package details
Install pi-task-orientation from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-task-orientation- Package
pi-task-orientation- Version
2.1.0- Published
- Aug 13, 2026
- Downloads
- 459/mo · 35/wk
- Author
- tomoyo123
- License
- MIT
- Types
- extension
- Size
- 39.1 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./extensions"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-task-orientation
A pi extension that turns "orientation" from a one-shot startup ritual into a continuous task loop, built for weak reasoning models (e.g. deepseek-v4-flash) that ignore soft instructions. v2 replaces the v1 task_orientation tool with a gated plan() + a live task_todo() list, mid-task checkpoints, and a next-request continuation nudge.
Why
Two chronic problems in agentic coding:
- Skills get skipped: with progressive disclosure, the system prompt only lists skill names + one-line descriptions. A model that never decides to
reada SKILL.md effectively ignores the skill system. - AGENTS.md rules get silently ignored: the full AGENTS.md is injected into the system prompt, but as reference context — nothing forces the model to analyze it, so "always-applicable" rules are followed inconsistently and "conditional" rules (e.g. worklog updates) are dropped without anyone noticing.
v1 forced a one-shot orientation at the start of every request. It worked, but every new message re-armed the gate, and the gate could be gamed with ["none"]. v2 fixes both: the gate now fires once per task, and the unlock action is the deliverable (a real plan — there is no cheap "none" escape).
How it works
┌─ Instruction before_agent_start new task → arm gate + inject plan() directive
│ continuation → no gate + inject continue nudge
├─ Enforcement tool_call block every tool until plan() is called
├─ Delivery plan() skills + AGENTS.md analysis + execution checklist
├─ Execution (free) task_todo() keeps the checklist live; load_skill mid-task
├─ Observation turn_end + context compact checkpoint: status line + update/AGENTS.md nudge
└─ Continuation agent_end archives completed lists; leftovers continue at the next request
The state machine (gate = once per task, not per message)
before_agent_start:
activeTodo == null or all terminated → NEW TASK: arm gate, inject plan() directive
otherwise → CONTINUATION: no gate, inject continue nudge
activeTodolives in the extension's state and in everyplan()/task_todo()tool-resultdetails(branch-safe; survives/fork).- On
session_start/session_tree/session_compactthe state is rebuilt from session history, so a mid-task/compactor/reloaddoes not lose the checklist. - On task completion the final list is archived via
appendEntry(audit trail).
plan() — the gated mandatory first step
Called before any other tool on a fresh task. Three deliverables in one call:
plan({
skills: ["code-review"], // matching skills, or [] — /skill: loaded ones are auto-skipped
reason: "covers the review part",
skipped_rules: [{ rule: "worklog update", reason: "no files changed yet" }], // or []
todos: [
{ title: "read the diff", status: "in_progress" }, // at most one in_progress
{ title: "review per skill", status: "pending" }
],
})
- Skills: chosen SKILL.md files are injected in full (no
readneeded, cannot be skipped). Already-loaded skills (manual/skill:name) are never re-injected. - AGENTS.md rules are BINDING: lack of forceful wording does not downgrade a rule. Conditional rules are recorded via
skipped_rulesand re-checked at checkpoints when they become triggered (e.g. after modifying files). - Todos must be a real execution checklist — there is no throwaway value like
"none"; the cheapest way to unlock the gate is to produce a genuine plan.
task_todo() — live updates during execution
task_todo({ action: "update", id: 3, status: "done" })
task_todo({ action: "update", id: 3, status: "blocked" })
task_todo({ action: "add", title: "also fix the README", status: "pending" })
task_todo({ action: "load_skill", skills: ["diagnosing-bugs"] })
Enforces two rules: at most one item in_progress (the model must close the current item before opening another), and statuses follow the situation (finished → done, superseded or unneeded → cancelled, cannot proceed now → blocked, no longer blocked → pending, new work → new items — per task_todo's status rules). load_skill injects a new skill's full instructions mid-task without re-arming the gate.
Checkpoints (turn_end → context)
After every execution turn, a compact status line is injected before the next LLM call:
[checkpoint] Done: 2 · In progress: #3 "implement login API" · Pending: 2 (next: #4 "write tests")
- Something completed or changed? Call task_todo to update it (or load_skill for a new skill).
- Did an AGENTS.md conditional rule trigger? Apply it now or add it to the todos.
- Otherwise just continue — no action needed.
Old orientation messages are pruned from context so only the latest stays; checkpoints are injected per-LLM-call and do not pollute session history.
agent_end continuation (no end-check)
agent_end always calls the completion archive: a list that is fully done/cancelled is archived and cleared (next request starts a new task), otherwise the list is kept and the next user message enters continuation mode — the injected continuation nudge asks the model to update the todos per the current state and the new message, then continue. Leftover in_progress/pending/blocked items are resolved there, not by a forced end-of-request round.
Known issues with deepseek-v4-flash (why this exists)
Measured against deepseek-v4-flash in controlled experiments:
- Thinking (chain-of-thought) defaults to English. Even when AGENTS.md says "think in Chinese", deepseek-v4-flash reasons in English (~71% of thinking blocks in our session). A descriptive rule is not enough — it only works as a strong imperative with examples. Phrase such rules as commands, and the BINDING wording in the plan() directive makes ignoring them a conscious act.
- Models circumvent soft gates. If a gate has a cheap legal exit (e.g.
task_orientation(["none"])), the model learns to take it every time — one session had 18 gate calls, all"none", zero skills loaded. v2'splan()has no cheap exit: the mandatoryreason,skipped_rules, and a realtodoslist make the unlock action equal to the deliverable. - Soft reminders get dropped. That is why the start is a hard gate, the end is a hard check, and the middle is frequent (every turn) rather than one-shot — a reminder the model sees every turn is much harder to ignore than a directive it saw once.
Design principles
- Gate = once per task: only a fresh task (or a finished one) re-arms the gate; "continue" messages do not.
- Unlock = deliverable: the cheapest legal plan() is a genuine plan, not a token call.
- State owned by the harness:
activeTodolives in extension state and tool-resultdetails— the model edits via tools, the harness persists, echoes, and reconstructs across/compact//reload//fork. - Hard at both ends, free in the middle: start gate + end check are the two mechanically-detectable anchors; in between, no per-tool interference, only per-turn nudges.
- Auditable: skill choices, AGENTS.md
skipped_rules, and the archived todo list are all recorded in session history. - Generic, not special-cased: the extension never names specific skills or rules (no hardcoded "diagnosing-bugs" or "worklog"); everything is derived from
<available_skills>and the project's AGENTS.md.
Manual skills (/skill:name)
- Visible skill: content is already in the user message;
plan()skips re-injection automatically, and the model may still add other matching skills. - Invisible skill (
disable-model-invocation): also already in context via/skill:expansion; the gate only requires oneplan()call (with[]or other skills), then execution is free. No extra friction beyond that single orientation call.
Known limitations (v1)
- A model can still produce a hollow
todoslist to open the gate. The counterweights are the mandatoryreason/skipped_rules, the checkpoint echo (a fake plan is visibly wrong), and the audit trail. A "confirm the plan" approval step is a planned v3 enhancement. - Re-planning on continuation messages is model-voluntary (no gate) — by design, to keep the gate rare.
- "Todos all terminated but a conditional rule (e.g. worklog) was forgotten" is not mechanically catchable; it relies on the BINDING wording and checkpoint nudges.
- In the armed window a weak model may still try 1–2 other tools before calling
plan(); each attempt is one blocked round-trip.
Install
pi install npm:pi-task-orientation
or copy extensions/task-orientation.ts into ~/.pi/agent/extensions/ and /reload.
Migration from v1
pi-task-orientation@2 supersedes @1. The task_orientation tool is gone; the system prompt directive now points to plan() / task_todo().
- Update to
2.0.0(pi install npm:pi-task-orientation@2or replace the local file). /reload.- Existing sessions are compatible — v2 reconstructs task state from session history.
Development
# strict type check (uses types-shim.d.ts + tsconfig.check.json for local resolution)
npx -y -p typescript tsc -p tsconfig.check.json
# syntax/transpile check (what the pi runtime does)
npx -y esbuild extensions/task-orientation.ts --bundle --format=esm --platform=node \
--external:@earendil-works/* --external:typebox --outfile=/tmp/to-check.js
License
MIT
中文说明
这是什么:一个让"定向"从一次性仪式变成持续任务循环的 pi 扩展。v2 用门控的 plan()(技能 + AGENTS.md 分析 + 执行清单三合一)取代 v1 的 task_orientation,新增 task_todo() 执行期更新、turn-end 检查点、agent-end 收尾兜底。
核心改进:
- 门控从"每条消息"降到"每个任务":只有新任务(或任务完成后的下一条消息)才武装门控;"继续"类消息不武装,直接延续。
- 解锁 = 交付物:
plan()没有["none"]这种廉价出口——最便宜的解锁就是写出一份真实清单。堵死了 v1 README 记录的"18 次全 none"绕过。 - 两端硬、中间自由:起点 plan 硬门控 + 终点条件硬收尾(todo 未终结或 plan 从未调用时,只续跑一轮);执行期不干预工具,只靠每 turn 的紧凑检查点软提醒。
- 状态 harness 持有:清单存在扩展状态与工具结果
details,跨/compact/reload/fork可重建;任务完成时appendEntry存档审计。 - 通用不特化:不点名任何具体技能或规则(不硬编码"diagnosing-bugs"、"worklog"),一切从
<available_skills>与项目 AGENTS.md 动态推导。
手动 /skill:name:可见技能与不可见技能都因 /skill: 展开而全文已在上下文,plan() 自动跳过重复注入;不可见技能也只多付一次 plan 调用的代价即可自由执行。
已知限制(v1):空洞 todo 仍能解锁(靠 reason/skipped_rules 必填、检查点回显反噬与审计兜底,人工"确认计划"步骤列入 v3);延续模式的重排是软约束;"todo 全终结但漏了条件规则"机械上抓不到,靠 BINDING 措辞与检查点提醒。
从 v1 迁移:工具 task_orientation 已移除,升级到 2.0.0 后 /reload 即可;v2 会从会话历史重建任务状态,旧会话兼容。