Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assets/agents/gentle-ai-explore.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ tools:

You are the read-only explorer for generic ODD work.

Map relevant files, symbols, relationships, and uncertainty within the parent-provided scope.
Map relevant files, symbols, relationships, and uncertainty within the parent-provided scope. When the parent supplies an ODD feature document, read it until `## Log` for the requirements.

- For structural questions, use the cwd-scoped `codegraph` tool before broad filesystem searches. Initialize the workspace index with `operation: "init"` when it is absent, then use `query` or `explore`; never ask it to target another path.
- `codegraph` may create or update only the current workspace `.codegraph/` index. This is the sole permitted mutation; all tracked files, source files, and other project content remain read-only.
Expand Down
2 changes: 2 additions & 0 deletions assets/agents/gentle-ai-verify.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Inspect relevant evidence and execute only exact test, build, or lint commands e

For behavior changes with applicable runnable deterministic tests and a clear expected outcome, test-first is the default: assess observed RED before implementation, observed GREEN afterward, and focused checks after refactor. Do not infer RED from a test file existing or claim GREEN without observed execution. For passive documentation, non-testable changes, an unavailable runner, or no meaningful RED, assess the stated exception and proportionate ordinary functional or structural verification. Test presence alone is not applicability; never demand a TUI or chat toggle, invent lifecycle evidence, or skip checks.

When the parent supplies an ODD feature document, read all of it, including the verbatim user entries in `## Log`, and return a verdict per `S#`: met, unmet, or unverified, with evidence. Run the spec's example commands when the parent authorized them; when an example mutates state, run it only against isolated state the parent named (for example a temporary data file), then compare the exact output and error text with the spec. Passing tests never prove an `S#` whose example was not executed.

- Do not edit, write, or fix findings.
- Do not run unapproved commands, alter an authorized command, install dependencies, or mutate repository state. Authorized commands may create only outputs the parent explicitly identified as expected.
- Treat every unexpected mutation as a blocker: report it, but do not clean it up or fix it.
Expand Down
2 changes: 1 addition & 1 deletion assets/agents/gentle-ai-worker.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Before repository work:

1. Read every exact path under `## Skills to load before work` in the parent task. Do not rediscover the skill registry.
2. Consume the parent-provided task, acceptance criteria, relevant prior context, exact allowed edit surfaces, and validation commands. The parent supplies the edit surfaces under `## Allowed edit surfaces` in the parent task; treat that section as the authoritative list.
Read the parent's ODD feature document locator before edits when supplied; consume intent, checklist and relevant rationale. Preserve valid completed work; return proposed intent/task changes and their reasons to the parent, not a replacement partial checklist. Findings do not authorize scope expansion.
Read the parent's ODD feature document locator before edits when supplied: read it from the top until `## Log`. Its `## Specs` are authoritative over any summary in the handoff, and their quoted strings, error messages, and examples are exact. Report in `summary` which `S#` the change covers and any linked `S#` it could not satisfy. Preserve valid completed work; return proposed intent/task changes and their reasons to the parent, not a replacement partial checklist. Findings do not authorize scope expansion.
3. Inspect the working tree and preserve pre-existing changes. Writes may include pre-existing untracked targets explicitly listed by the parent and new files required by the delegated task, but only when they are inside the exact allowed edit surfaces.
4. Preserve every unrelated tracked or untracked file. Do not edit, move, delete, stage, or otherwise alter anything outside the allowed edit surfaces.
5. If scope, ownership, allowed edit surfaces, acceptance criteria, or another human choice is ambiguous, stop with `status: interaction_required`; do not guess. Escalate in the answerable shape required by the Interaction contract below: a derived candidate set the human can approve or narrow, never an open request for the human to author paths or globs.
Expand Down
4 changes: 2 additions & 2 deletions assets/orchestrator-delegation.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The sections below bind generic delegation rules to Pi's concrete runtime. They

## Language Boundary — subagent-facing English + exceptions

Subagent-facing prompts should be written in English by default, even when the user speaks Spanish. Translate the user's request into concise English before delegation. This keeps token usage lower and gives built-in/project subagents a consistent operating language without changing the user-facing persona.
Subagent-facing prompts should be written in English by default, even when the user speaks Spanish. Write the handoff instructions in English, but never translate, condense, or paraphrase the user's requirements: pass them by reference to the feature document's `## Specs` (`Spec: odd/tasks/<feature>.md (read until "## Log"). Do T#; S#.`), or include the user's request verbatim when no feature document exists. This keeps orchestrator output small and gives built-in/project subagents a consistent operating language without changing the user-facing persona or losing exact requirements.

Exceptions:

Expand All @@ -72,7 +72,7 @@ These instructions apply to all development work. Preserve the existing direct/d

Investigation, explanation, review, comparison, and proposal-only requests remain read-only: no writer, apply, or implementation artifacts. Ambiguous or conditional change intent requires one clarification; stop and wait. Explore existing code and requirements proportionately first. Research findings and automatic execution pace never authorize mutations.

Small, understood work creates no durable task artifacts. Substantial means coordinated steps or progress worth recovering, not a line threshold. For substantial authorized implementation, automatically create the feature document after exploration, without a task or storage permission prompt. Follow `orchestrator-memory.md` for the file and full Engram recovery copy, automatic updates, truthful checkoffs, and resume. Keep the parent responsible for reconciliation; bounded workers receive the document locator, relevant intent, task IDs, authorized scope and checks, not authority over unrelated tasks; they read the document before edits.
Small, understood work creates no durable task artifacts. Substantial means coordinated steps or progress worth recovering, not a line threshold. For substantial authorized implementation, automatically create the feature document after exploration, without a task or storage permission prompt. Follow `orchestrator-memory.md` for the file and full Engram recovery copy, automatic updates, truthful checkoffs, and resume. Keep the parent responsible for reconciliation; bounded workers receive the document locator, task IDs, linked `S#`, authorized scope and checks, not authority over unrelated tasks; they read the document until `## Log` before edits and report which `S#` they covered. A rejected or resumed handoff is repaired and resent with the same content, never shortened. Reproduce a user-reported failure by running the reported example before deciding it already works; reading code is not reproduction.

Use about 400 authored changed lines per ODD task only as a planning heuristic, counting additions plus deletions. Keep the smallest coherent behavior with its tests and docs. This is not a task acceptance criterion, hard cap, counter-trigger, automatic stop, forced split, or RDD trigger. If the correct clear solution naturally exceeds it, briefly explain why and continue without size-only rework loops. Never delete spaces, blank lines, or comments for cosmetic line savings; never omit tests, minify, add gratuitous abstractions, or split artificially to fit the heuristic. Forward this same advisory-only instruction when delegating tasks to subagents. The delivery budget below reads the accumulated branch, not this per-task heuristic. Existing PR size gates remain unchanged; follow repository policy.

Expand Down
13 changes: 10 additions & 3 deletions assets/orchestrator-memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ Bind this to the parent Pi session only, on organic progress/recovery. Not alway

### Organic feature continuity

For substantial authorized organic implementation, the parent maintains `odd/tasks/<feature-name>.md` and an Engram recovery copy under topic `odd/<feature-name>/tasks`, scoped to the current project. Use a descriptive filename-safe feature name, reuse the same identity, and never overwrite another feature. Keep one feature document, not a separate plan file or topic: objective, problem, why, scope, constraints, actionable checklist with stable task IDs, acceptance criteria and checks, progress, verification evidence, and next step. Include concise rationale for meaningful accepted changes. Routine corrections stay with their tasks; no exhaustive decision journal. Mirror the full current document and repository-relative file locator, not only a summary or completion notice.
For substantial authorized organic implementation, the parent maintains `odd/tasks/<feature-name>.md` and an Engram recovery copy under topic `odd/<feature-name>/tasks`, scoped to the current project. Use a descriptive filename-safe feature name, reuse the same identity, and never overwrite another feature. Keep one feature document, not a separate plan file or topic. It is the specification subagents read by reference, so keep this fixed order, stable content first and the growing log last:

Accepted user, review, or verification changes automatically update affected intent and TODOs: preserve valid completed and unrelated work; add genuinely new tasks or reopen invalidated items with a reason, and revise their checks. Findings alone never authorize scope expansion or automatic acceptance. New business scope still requires user authorization. Check off only observed outcomes with applicable proof; record failed, unavailable, skipped, or pending checks honestly. The parent merges bounded worker results rather than replacing the entire feature with one worker's partial view.
1. A header of two or three lines: objective, branch, delivery strategy, and test runner.
2. `## Specs`: numbered `S1`..`Sn` requirements, constraints, and acceptance criteria with their checks. Quote the user's exact strings, error messages, commands, and examples verbatim, in the user's language; you may number and order them, but never summarize or reword those fragments. Do not add requirements the user never asked for; mark assumptions as assumptions.
3. `## Tasks`: one line per task, using stable task IDs, with its linked `S#`, route (inline or delegated), status, and commit identity or RED/GREEN evidence.
4. `## Log`: the logbook. `L1` holds the user's original request verbatim; later user corrections are logged verbatim with their date. Problem analysis, rationale for meaningful accepted changes, verification evidence, progress, and next step go here. Routine corrections stay brief; no exhaustive decision journal.

Mirror the full current document and repository-relative file locator, not only a summary or completion notice.

Accepted user, review, or verification changes automatically update affected intent and TODOs, unlike a process that regenerates every artifact: a requirement change appends its verbatim `## Log` entry, rewrites only the affected `S#`, and reopens only its linked task; preserve valid completed and unrelated work; add genuinely new tasks or reopen invalidated items with a reason, and revise their checks. Findings alone never authorize scope expansion or automatic acceptance. New business scope still requires user authorization. Check off only observed outcomes with applicable proof; record failed, unavailable, skipped, or pending checks honestly. The parent merges bounded worker results rather than replacing the entire feature with one worker's partial view.

Persist local progress first, then mirror through the existing injected Engram save tool. Read back both writes; they are not atomic. If Engram is unavailable, preserve local progress and explicitly mark the mirror pending; do not claim persistence succeeded or block unrelated safe work. Resynchronize when available. If a file write is unsafe or unavailable, preserve existing state and report the limitation. Preserve both versions on irreconcilable edits and ask only about the real conflict; never silently prefer a newer timestamp.

On resume, use `mem_context`, then project/feature-scoped `mem_search`, and `mem_get_observation` for the full saved document; read the actual task file. Do not infer active work from the newest global memory. Reconcile current requirements, code, and proof before continuing the next unfinished task. Preserve pending mirrors and conflicting edits; a missing copy is not permission to overwrite surviving progress. Use the injected equivalents of these existing memory tools, never invent availability.

Before implementation or resume, the parent reads both the actual file and full observation, reconciles them, and passes the locator and relevant context; workers read the document before edits. Small work without a document still receives its authorized scope and checks.
Before implementation or resume, the parent reads both the actual file and full observation, reconciles them, and passes the locator, task IDs, and linked `S#`; workers read the document until `## Log` before edits. Small work without a document still receives its authorized scope and checks.

The existing `todo` tool is the required session/UI projection for substantial ODD, not a third authority. After reconciling and writing the durable file and Engram copy, create or rebuild the visible `todo` list from the same feature tasks before the first source write; after every task transition and material plan change, update both durable copies and the visible projection in the same turn; its replay or completed-list clearing must not delete or replace the durable file or Engram copy. If the projection is unavailable, record that limitation without pretending it is synchronized. Small/read-only work does not acquire an ODD artifact or todo list merely because the UI can display tasks.

Expand Down
23 changes: 16 additions & 7 deletions extensions/gentle-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { CARD_TONE, renderCard } from "../lib/shell-card.ts";
import { openInExternalEditor } from "./gentle-shell.ts";
import { resolveGentlePiAgentHome, gentlePiConfigHome } from "../lib/agent-home.ts";
import { resolveProfilePin, resolveUnversionedProjectProfile } from "../lib/agent-profile-pin.ts";
import { allowedEditSurfaces, isDevelopmentSurface, isGenericBoundedWriter, prepareBoundSessionRepository, rejectUnscopedBoundedWriterDispatch, safeBootstrapDirectory, sessionRepositoryAuthority } from "../lib/bounded-writer-admission.ts";
import { allowedEditSurfaces, inheritAllowedEditSurfaces, isDevelopmentSurface, isGenericBoundedWriter, prepareBoundSessionRepository, rejectUnscopedBoundedWriterDispatch, safeBootstrapDirectory, sessionRepositoryAuthority } from "../lib/bounded-writer-admission.ts";
import { CHILD_METRICS_EVENT, CHILD_METRICS_REVOKED, childEvent, launchSelection, type LaunchSelection } from "../lib/runtime-metrics-children.ts";
import { runtimeMetricsEnvAllows, type RuntimeMetricsPolicyDeps } from "../lib/runtime-metrics-policy.ts";

Expand Down Expand Up @@ -1117,6 +1117,14 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
return stored?.task;
};

// A guessed id ("1") leads back to real ids instead of a dead end, so the
// parent retries the same call rather than re-summarizing it (gentle-shell#1713).
const unknownTask = (id: unknown, ctx: ExtensionContext | undefined) => {
const recent = [...store.list(ctx?.sessionManager?.getSessionId() ?? "")].sort((a, b) => b.createdAt - a.createdAt).slice(0, 5);
const hint = recent.length ? ` Recent task ids: ${recent.map((task) => `${task.id} (${task.agent})`).join(", ")}.` : "";
return text(`Error: no task ${String(id)}.${hint}`, { error: "unknown task" });
};

// Restores this exact session's own finished subagents as visible history
// on an explicit resume, or on startup into a session that already has
// entries -- never on new, fork, or reload (see the session_start handler's
Expand Down Expand Up @@ -1636,14 +1644,14 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
},
);

tool("status", "Report the status of one subagent task.", { required: ["task_id"], properties: { task_id: { type: "string" } } }, async (params) => {
tool("status", "Report the status of one subagent task.", { required: ["task_id"], properties: { task_id: { type: "string" } } }, async (params, ctx) => {
const task = await resolveTask(String(params.task_id));
return task ? text(describeTask(task), taskDetails(task)) : text(`Error: no task ${String(params.task_id)}`, { error: "unknown task" });
return task ? text(describeTask(task), taskDetails(task)) : unknownTask(params.task_id, ctx);
});

tool("result", "Return the final answer of a finished subagent task, or its current state if it is still running.", { required: ["task_id"], properties: { task_id: { type: "string" } } }, async (params) => {
tool("result", "Return the final answer of a finished subagent task, or its current state if it is still running.", { required: ["task_id"], properties: { task_id: { type: "string" } } }, async (params, ctx) => {
const task = await resolveTask(String(params.task_id));
if (!task) return text(`Error: no task ${String(params.task_id)}`, { error: "unknown task" });
if (!task) return unknownTask(params.task_id, ctx);
// The parent just pulled a finished result; its pending completion must
// never be replayed on top of it.
if (isFinished(task.status)) {
Expand Down Expand Up @@ -1683,7 +1691,7 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
async (params, ctx, signal) => {
if (Object.hasOwn(params, "sdd_change") || Object.hasOwn(params, "remediation") || Object.hasOwn(params, "research_selection")) return text("Error: retired SDD delegation is not supported.", { error: "retired SDD delegation" });
const previous = await resolveTask(String(params.task_id));
if (!previous) return text(`Error: no task ${String(params.task_id)}`, { error: "unknown task" });
if (!previous) return unknownTask(params.task_id, ctx);
if (retiredSddAgent(previous.agent)) return text("Error: retired SDD agents cannot be continued.", { error: "retired SDD delegation" });
if (!isFinished(previous.status) || !previous.sessionPath) return text(`Error: task ${previous.id} cannot be continued yet (${previous.status}).`, { error: "not continuable" });
// Continuing acts on the previous result, so any pending completion for
Expand All @@ -1694,7 +1702,8 @@ export default function gentleAgents(pi: ExtensionAPI, env: NodeJS.ProcessEnv =
if (!agent) return text(`Error: subagent "${previous.agent}" is no longer defined.`, { error: "unknown agent" });
const mode = (params.mode as AgentMode | undefined) ?? (previous.mode as AgentMode);
const foreignContinuation = foreignTasks.has(previous.id);
return launch(ctx, await buildRequest(ctx, agent, String(params.prompt ?? ""), typeof params.label === "string" ? params.label : undefined, typeof params.context === "string" ? params.context : undefined, mode, previous.sessionPath, foreignContinuation ? undefined : previous.cwd, signal, foreignContinuation ? previous.cwd : undefined), signal);
const prompt = inheritAllowedEditSurfaces(previous.agent, String(params.prompt ?? ""), params.context, previous.prompt);
return launch(ctx, await buildRequest(ctx, agent, prompt, typeof params.label === "string" ? params.label : undefined, typeof params.context === "string" ? params.context : undefined, mode, previous.sessionPath, foreignContinuation ? undefined : previous.cwd, signal, foreignContinuation ? previous.cwd : undefined), signal);
},
);

Expand Down
Loading
Loading