killeros 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +27 -5
- package/agents/debugger.md +0 -1
- package/agents/documenter.md +0 -1
- package/agents/planner.md +0 -1
- package/agents/reviewer.md +0 -1
- package/agents/scout.md +0 -1
- package/agents/security.md +0 -1
- package/agents/tester.md +0 -1
- package/agents/worker.md +0 -1
- package/package.json +5 -1
- package/subagent-budget.ts +65 -0
- package/subagent-lifecycle.ts +506 -0
- package/subagent-process.ts +485 -0
- package/subagent-ui.ts +210 -0
- package/subagents.ts +649 -269
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to KillerOS are documented here.
|
|
4
4
|
|
|
5
|
+
## [1.4.3] - 2026-08-01
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Added child-runtime tool budgets for read-only roles, with a soft finalization nudge and hard blocking for read and web tools after 32 calls.
|
|
10
|
+
- Added bounded child report instructions and kept read-tool budgets cumulative across steering restarts.
|
|
11
|
+
- Lowered the default child quota to 250,000 tokens and $5, and exposed child tool-call counts in results.
|
|
12
|
+
|
|
13
|
+
## [1.4.2] - 2026-08-01
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Added named child threads with inspectable lifecycle state, Active/Done views, steering, interruption, collection, and closure controls.
|
|
18
|
+
- Added isolated child-process resource guards for wall time, JSONL lines, retained trace, stderr, output, token quota, cost quota, task count, and concurrency.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Replaced routine child turn limits with natural completion plus named resource guards.
|
|
23
|
+
- Preserved partial traces and handoffs when a child fails, stops, or reaches a limit.
|
|
24
|
+
|
|
5
25
|
## [1.4.1] - 2026-08-01
|
|
6
26
|
|
|
7
27
|
### Added
|
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ pi install git:github.com/KyrosHendrix/pi-KillerOS
|
|
|
33
33
|
Pin an install to a release:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
pi install git:github.com/KyrosHendrix/pi-KillerOS@v1.4.
|
|
36
|
+
pi install git:github.com/KyrosHendrix/pi-KillerOS@v1.4.3
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
Add `-l` to either command for a project-only install. Restart Pi after installing.
|
|
@@ -47,7 +47,7 @@ Add `-l` to either command for a project-only install. Restart Pi after installi
|
|
|
47
47
|
- Responsive footer with polished model/provider identity, plain-language context, and active goal state remaining; reasoning, Git branch, elapsed time, cost, and path cut down by available width
|
|
48
48
|
- `/variants` selector and direct reasoning-level arguments
|
|
49
49
|
- Codex-style `/goal` for durable long-running objectives with pause, resume, edit, clear, automatic continuation, and explicit completion
|
|
50
|
-
- Pi-native `subagent` tool with
|
|
50
|
+
- Pi-native `subagent` tool with named, inspectable child threads, Markdown roles, explicit read/write boundaries, parent controls, bounded resources, and cancellation propagation
|
|
51
51
|
- Claude Code-style `/init` that scans the repository and generates a concise root `AGENTS.md` without setup questions
|
|
52
52
|
- `question` tool with filtering, proposal previews, keyboard selection, custom answers, history, cancellation, and resize-safe rendering
|
|
53
53
|
- Mid-prompt slash completion with current Pi `0.82.1` commands, extensions, prompts, and skills
|
|
@@ -95,7 +95,7 @@ KillerOS ships `planner`, `reviewer`, `scout`, and `security` as read-only roles
|
|
|
95
95
|
2. Personal: `~/.pi/agent/agents/*.md`
|
|
96
96
|
3. Trusted project: `<repo>/.pi/agents/*.md`
|
|
97
97
|
|
|
98
|
-
The default `agentScope: "user"` uses bundled and personal roles. Use `"project"` or `"both"` to opt into trusted project roles; a selected project override requires interactive confirmation. Role frontmatter requires `name`, `description`, `access`, and an explicit `tools` list. Optional fields are `model`, `thinking`,
|
|
98
|
+
The default `agentScope: "user"` uses bundled and personal roles. Use `"project"` or `"both"` to opt into trusted project roles; a selected project override requires interactive confirmation. Role frontmatter requires `name`, `description`, `access`, and an explicit `tools` list. Optional fields are `model`, `thinking`, and `timeoutMs`. Every bundled role shows `model: inherit` and `thinking: inherit` as editable placeholders. Replace them with an available `provider/model` and a separate thinking level when you want to pin a role; `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max` are checked against that model’s supported capabilities.
|
|
99
99
|
|
|
100
100
|
The tool supports a single `agent` + `task`, parallel `tasks`, or a sequential `chain` whose task text may include `{previous}`. A call can also set `model` and `thinking` for every task, overriding role settings; use `inherit` to fall back to each role and then the active parent model. For example:
|
|
101
101
|
|
|
@@ -103,7 +103,29 @@ The tool supports a single `agent` + `task`, parallel `tasks`, or a sequential `
|
|
|
103
103
|
{"agent":"reviewer","task":"Review the change","model":"provider/model","thinking":"high"}
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
Use the separate `model` and `thinking` fields for new configuration. The older `provider/model:thinking` model form remains accepted. Children run as ephemeral `pi --mode json -p --no-session` processes with explicit local tools plus `web_search`, `source_check`, `fetch_content`, and `get_search_content`. Each child explicitly loads `npm:pi-web-access
|
|
106
|
+
Use the separate `model` and `thinking` fields for new configuration. The older `provider/model:thinking` model form remains accepted. Children run as ephemeral `pi --mode json -p --no-session` processes with explicit local tools plus `web_search`, `source_check`, `fetch_content`, and `get_search_content`. Each child explicitly loads `npm:pi-web-access` and the KillerOS child-budget hook, discovers available skills, and keeps arbitrary extensions and prompt templates disabled; project-local skills load only when the parent project is trusted. Every bundled role is instructed to load the most relevant `SKILL.md`, work in bounded passes, and report after its first useful evidence. KillerOS allows at most eight tasks, four parallel readers, ten minutes, a 32 MiB JSONL line, 2 MiB retained trace, 64 KiB stderr, 50 KiB returned output, 250,000 tokens, and $5 per child. Read-only children receive a 24-call soft and 32-call hard tool budget that blocks read and web tools after the hard limit; final reports remain allowed. Esc cancellation terminates active children and escalates after five seconds.
|
|
107
|
+
|
|
108
|
+
### Thread lifecycle
|
|
109
|
+
|
|
110
|
+
Each delegated task creates a named child thread. Its contract records the parent ID, child ID, role, prompt, model, requested capability boundary, trace, usage, and result state. Roles define the child’s access and tools; they do not own lifecycle controls or grant new filesystem powers. The parent owns scope, waits, inspection, steering, collection, and closure.
|
|
111
|
+
|
|
112
|
+
Threads move through `queued`, `active`, `done`, `failed`, `stopped`, and `closed`. The parent renders separate **Active** and **Done** lists. Active threads show their name, task, model, usage, and direct controls. Done threads keep their handoff and trace available until the parent closes them.
|
|
113
|
+
|
|
114
|
+
The parent can inspect a thread’s prompt, role, model, tools, trace, usage, and handoff; steer an active thread with one bounded follow-up; interrupt one child or all active children; collect a concise handoff into parent context; and close a finished or stopped thread. An interrupt preserves the partial trace, states the reason, and reports the handoff as partial rather than successful.
|
|
115
|
+
|
|
116
|
+
A child completes naturally when it returns a final answer. Routine turn caps do not end useful work. Named resource guards still stop unsafe growth: wall time, output bytes, retained trace, stderr, quota, read-tool calls, task count, and concurrency. Read-tool budgets are enforced inside the child process, so the model receives a finalization nudge and a blocked-tool result instead of being killed while it is still researching. A guard reports its cause and returns any partial work clearly. Esc cancellation terminates active children and escalates after five seconds.
|
|
117
|
+
|
|
118
|
+
The replacement lifecycle has nine phases:
|
|
119
|
+
|
|
120
|
+
1. **Dispatch:** create a named thread and store its contract before launch.
|
|
121
|
+
2. **Track:** maintain lifecycle states and Active/Done visibility.
|
|
122
|
+
3. **Inspect:** keep the trace in the child thread, not the parent context.
|
|
123
|
+
4. **Steer:** append a bounded parent follow-up to an active thread.
|
|
124
|
+
5. **Interrupt:** stop one or all active children while preserving partial work.
|
|
125
|
+
6. **Collect:** return a concise handoff while retaining the expanded trace.
|
|
126
|
+
7. **Bound:** apply named resource guards instead of a routine turn stop.
|
|
127
|
+
8. **Close:** remove a finished or stopped thread from the workspace without deleting its result record.
|
|
128
|
+
9. **Prove:** test identity, visibility, controls, natural completion, guards, partial handoffs, and closure.
|
|
107
129
|
|
|
108
130
|
## Configuration
|
|
109
131
|
|
|
@@ -141,7 +163,7 @@ The package manifest lists Pi’s built-in modules as peer dependencies, so npm
|
|
|
141
163
|
|
|
142
164
|
The [`pi-package`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md) keyword makes a published npm release visible in Pi’s package catalog.
|
|
143
165
|
|
|
144
|
-
For the current unreleased `1.4.
|
|
166
|
+
For the current unreleased `1.4.3`, publish after the validation checks pass:
|
|
145
167
|
|
|
146
168
|
```bash
|
|
147
169
|
npm login
|
package/agents/debugger.md
CHANGED
package/agents/documenter.md
CHANGED
package/agents/planner.md
CHANGED
package/agents/reviewer.md
CHANGED
package/agents/scout.md
CHANGED
package/agents/security.md
CHANGED
package/agents/tester.md
CHANGED
package/agents/worker.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "killeros",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "A production-hardened TUI and workflow extension for the Pi coding agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"files": [
|
|
23
23
|
"Killeros.ts",
|
|
24
24
|
"subagents.ts",
|
|
25
|
+
"subagent-lifecycle.ts",
|
|
26
|
+
"subagent-process.ts",
|
|
27
|
+
"subagent-budget.ts",
|
|
28
|
+
"subagent-ui.ts",
|
|
25
29
|
"agents/*.md",
|
|
26
30
|
"themes/killeros.json",
|
|
27
31
|
"README.md",
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ExtensionAPI, ToolCallEventResult } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
export const CHILD_TOOL_BUDGET_ENV = "PI_KILLEROS_TOOL_BUDGET";
|
|
4
|
+
|
|
5
|
+
export interface ChildToolBudget {
|
|
6
|
+
soft?: number;
|
|
7
|
+
hard: number;
|
|
8
|
+
block: "*" | string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function parseChildToolBudget(value: string | undefined): ChildToolBudget | undefined {
|
|
12
|
+
if (!value?.trim()) return undefined;
|
|
13
|
+
try {
|
|
14
|
+
const parsed = JSON.parse(value) as Record<string, unknown>;
|
|
15
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return undefined;
|
|
16
|
+
const hard = parsed.hard;
|
|
17
|
+
const soft = parsed.soft;
|
|
18
|
+
const block = parsed.block;
|
|
19
|
+
if (typeof hard !== "number" || !Number.isSafeInteger(hard) || hard < 1) return undefined;
|
|
20
|
+
if (soft !== undefined && (typeof soft !== "number" || !Number.isSafeInteger(soft) || soft < 1 || soft > hard)) return undefined;
|
|
21
|
+
if (block !== "*" && (!Array.isArray(block) || block.length === 0 || block.some((tool) => typeof tool !== "string" || !tool.trim()))) return undefined;
|
|
22
|
+
return {
|
|
23
|
+
hard,
|
|
24
|
+
...(soft === undefined ? {} : { soft }),
|
|
25
|
+
block: block === "*" ? "*" : [...new Set((block as string[]).map((tool) => tool.trim()))],
|
|
26
|
+
};
|
|
27
|
+
} catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function softNudge(budget: ChildToolBudget, calls: number): string {
|
|
33
|
+
return `Tool budget soft limit reached after ${calls} tool call${calls === 1 ? "" : "s"} (soft ${budget.soft}, hard ${budget.hard}). Stop starting new browsing/search work and finalize from the context you already have.`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function shouldBlock(budget: ChildToolBudget, toolName: string, calls: number): boolean {
|
|
37
|
+
return calls > budget.hard && (budget.block === "*" || budget.block.includes(toolName));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default function registerSubagentBudget(pi: ExtensionAPI): void {
|
|
41
|
+
const budget = parseChildToolBudget(process.env[CHILD_TOOL_BUDGET_ENV]);
|
|
42
|
+
if (!budget) return;
|
|
43
|
+
let calls = 0;
|
|
44
|
+
let nudged = false;
|
|
45
|
+
const sendUserMessage = (pi as unknown as {
|
|
46
|
+
sendUserMessage?: (content: string, options: { deliverAs: "steer" }) => unknown;
|
|
47
|
+
}).sendUserMessage;
|
|
48
|
+
|
|
49
|
+
pi.on("tool_call", (event): ToolCallEventResult | void => {
|
|
50
|
+
calls += 1;
|
|
51
|
+
if (!nudged && budget.soft !== undefined && calls >= budget.soft) {
|
|
52
|
+
nudged = true;
|
|
53
|
+
try {
|
|
54
|
+
sendUserMessage?.(softNudge(budget, calls), { deliverAs: "steer" });
|
|
55
|
+
} catch {
|
|
56
|
+
// The hard block below remains authoritative if steering is unavailable.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!shouldBlock(budget, event.toolName, calls)) return undefined;
|
|
60
|
+
return {
|
|
61
|
+
block: true,
|
|
62
|
+
reason: `Tool budget hard limit reached after ${calls} tool calls (hard ${budget.hard}). Finalize from the context you already have.`,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|