Skip to content
Open
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 AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,5 @@ const table = sqliteTable("session", {
- Keep delivery vocabulary explicit. Prompts steer by default and promote at the next safe step boundary while the current drain requires continuation. An explicit `queue` input remains pending until the Session would otherwise become idle; promote one queued input at that boundary, then reevaluate continuation before promoting another. Promoting any new user input resets the selected agent's step allowance; a batch of steers resets it once.
- One step is one logical LLM call; its durable record covers only the model-visible span. Do not write "provider turn", and do not use bare "turn" for a single call: "turn" is reserved for the future assistant-turn unit containing all steps from prompt promotion until the session would go idle.
- Keep EventV2 replay owner claims separate from clustered Session execution ownership.
- Keep the Instructions algebra and built-ins in `src/instructions`; keep instruction producers with their observed domains, and keep Session History selection plus `InstructionCheckpoint` and `InstructionEntry` persistence Session-owned. `InstructionDiscovery` observes ambient global and upward-project instructions. The runner composes built-ins, discovery, guidance, and entries explicitly in `loadInstructions`; there is no instruction registry.
- Keep the Instructions algebra and built-ins in `src/instructions`; keep instruction producers with their observed domains, and keep Session History selection plus `InstructionCheckpoint` and `InstructionEntry` persistence Session-owned. `InstructionDiscovery` combines ambient global/upward-project instructions with durable path-local instructions discovered after successful reads. The runner composes built-ins, discovery, guidance, and entries explicitly in `loadInstructions`; there is no instruction registry.
- The durable `Instructions.Applied` record is what the model was last told, per instruction source. Reconciliation narrates drift through `session.instructions.updated` and never rewrites the baseline; only completed compaction rebaselines, while Session movement or committed revert resets the `InstructionCheckpoint`. Unavailable sources keep the model's prior belief, blocking only a Session's first instruction baseline.
9 changes: 5 additions & 4 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ _Avoid_: Prompt fragment
One API-managed, durable, per-Session instruction value. Its slash-free client key maps to the `api/<key>` **Instruction Source** key. Entries deliberately render to the model as mechanism-neutral `<context>` blocks: the model sees session context, not how it was attached.

**InstructionDiscovery**:
The Location-scoped service that observes ambient global and upward-project `AGENTS.md` files as one ordered aggregate **Instruction Source**.
The Location-scoped service that combines ambient global and upward-project `AGENTS.md` files with durable per-Session path-local `AGENTS.md` files discovered after successful reads.

**InstructionCheckpoint**:
The Session-owned durable instruction baseline, baseline sequence, and `Instructions.Applied` record used to prepare later Steps.
Expand Down Expand Up @@ -135,12 +135,13 @@ _Avoid_: Response envelope
- Completed compaction rebaselines the **InstructionCheckpoint** from current **Instructions** and removes earlier **Instruction Updates** from active projected model history while preserving durable audit history.
- A newly composed **Instruction Source** absent from **Applied Instructions** emits its baseline rendering once at the next **Safe Step Boundary**.
- **Unavailable Instruction Source** uses stale-while-revalidate semantics and is distinct from a successfully loaded absence, which may emit removal text.
- **InstructionDiscovery** observes ambient instructions as one ordered aggregate **Instruction Source**.
- **InstructionDiscovery** combines ambient instructions with durable path-local instructions as one ordered aggregate **Instruction Source**.
- Ambient discovery reads global and upward-project `AGENTS.md` files and honors `OPENCODE_DISABLE_PROJECT_CONFIG` for project files.
- After a successful internal file or directory read, nearby `AGENTS.md` files toward the Location root are injected once per Session as durable synthetic instruction messages.
- After a successful internal file or directory read, path-local discovery searches nearby `AGENTS.md` files toward the Location root and publishes `session.instructions.discovered` with the owning assistant message and Location. Projection freezes newly readable files per Session, and the next **Safe Step Boundary** admits the combined instruction change.
- Ambient files precede path-local files, duplicate paths are removed, and path-local files retain durable admission and discovery order.
- **InstructionEntry** stores API-managed per-Session JSON values. Each entry contributes one `api/<key>` **Instruction Source**, so adding, replacing, or removing an entry is reconciled at the next **Safe Step Boundary**.
- Location-scoped instruction producers naturally re-resolve when a moved Session next runs in its destination Location.
- Moving a Session resets its **InstructionCheckpoint**, so the destination must initialize a complete baseline before another prompt can promote. Committed revert also resets the checkpoint.
- Moving a Session resets its **InstructionCheckpoint** and path-local discoveries, so the destination must initialize a complete baseline before another prompt can promote. Committed revert also resets the checkpoint and removes path-local discoveries admitted after the revert boundary.
- Selected-agent available-skill guidance is an **Instruction Source** composed explicitly by the runner. It lists only names and descriptions permitted for that agent; skill bodies and locations are exposed only through the permission-checked `skill` tool.
- The selected agent and model are sampled when a **Step** starts. Changes admitted after that boundary apply to the next Step and do not restart the current Step.
- An agent switch that changes selected-agent guidance produces an **Instruction Update** while preserving the current baseline.
Expand Down
28 changes: 28 additions & 0 deletions packages/client/src/promise/generated/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,20 @@ export type SessionLogOutput =
readonly location?: { readonly directory: string; readonly workspaceID?: string }
readonly data: { readonly sessionID: string; readonly text: string }
}
| {
readonly id: string
readonly created: number
readonly metadata?: { readonly [x: string]: unknown }
readonly type: "session.instructions.discovered"
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
readonly location?: { readonly directory: string; readonly workspaceID?: string }
readonly data: {
readonly sessionID: string
readonly assistantMessageID: string
readonly location: { readonly directory: string; readonly workspaceID?: string }
readonly files: ReadonlyArray<{ readonly path: string; readonly content: string }>
}
}
| {
readonly id: string
readonly created: number
Expand Down Expand Up @@ -4473,6 +4487,20 @@ export type EventSubscribeOutput =
readonly location?: { readonly directory: string; readonly workspaceID?: string }
readonly data: { readonly sessionID: string; readonly text: string }
}
| {
readonly id: string
readonly created: number
readonly metadata?: { readonly [x: string]: unknown }
readonly type: "session.instructions.discovered"
readonly durable: { readonly aggregateID: string; readonly seq: number; readonly version: number }
readonly location?: { readonly directory: string; readonly workspaceID?: string }
readonly data: {
readonly sessionID: string
readonly assistantMessageID: string
readonly location: { readonly directory: string; readonly workspaceID?: string }
readonly files: ReadonlyArray<{ readonly path: string; readonly content: string }>
}
}
| {
readonly id: string
readonly created: number
Expand Down
95 changes: 92 additions & 3 deletions packages/core/schema.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"version": "7",
"dialect": "sqlite",
"id": "992b24b9-f3e9-41f5-87a5-4917d1423169",
"id": "4689ab8e-76e3-429e-832c-403de6b7de57",
"prevIds": [
"96e9fe64-660f-4a73-9414-b38bb7eac290"
"992b24b9-f3e9-41f5-87a5-4917d1423169"
],
"ddl": [
{
Expand Down Expand Up @@ -58,6 +58,10 @@
"name": "instruction_entry",
"entityType": "tables"
},
{
"name": "instruction_file",
"entityType": "tables"
},
{
"name": "message",
"entityType": "tables"
Expand Down Expand Up @@ -876,6 +880,66 @@
"entityType": "columns",
"table": "instruction_entry"
},
{
"type": "text",
"notNull": true,
"autoincrement": false,
"default": null,
"generated": null,
"name": "session_id",
"entityType": "columns",
"table": "instruction_file"
},
{
"type": "text",
"notNull": true,
"autoincrement": false,
"default": null,
"generated": null,
"name": "path",
"entityType": "columns",
"table": "instruction_file"
},
{
"type": "text",
"notNull": true,
"autoincrement": false,
"default": null,
"generated": null,
"name": "content",
"entityType": "columns",
"table": "instruction_file"
},
{
"type": "integer",
"notNull": true,
"autoincrement": false,
"default": null,
"generated": null,
"name": "message_seq",
"entityType": "columns",
"table": "instruction_file"
},
{
"type": "integer",
"notNull": true,
"autoincrement": false,
"default": null,
"generated": null,
"name": "discovered_seq",
"entityType": "columns",
"table": "instruction_file"
},
{
"type": "integer",
"notNull": true,
"autoincrement": false,
"default": null,
"generated": null,
"name": "position",
"entityType": "columns",
"table": "instruction_file"
},
{
"type": "text",
"notNull": false,
Expand Down Expand Up @@ -1651,6 +1715,21 @@
"entityType": "fks",
"table": "instruction_entry"
},
{
"columns": [
"session_id"
],
"tableTo": "session",
"columnsTo": [
"id"
],
"onUpdate": "NO ACTION",
"onDelete": "CASCADE",
"nameExplicit": false,
"name": "fk_instruction_file_session_id_session_id_fk",
"entityType": "fks",
"table": "instruction_file"
},
{
"columns": [
"session_id"
Expand Down Expand Up @@ -1786,6 +1865,16 @@
"entityType": "pks",
"table": "instruction_entry"
},
{
"columns": [
"session_id",
"path"
],
"nameExplicit": false,
"name": "instruction_file_pk",
"entityType": "pks",
"table": "instruction_file"
},
{
"columns": [
"session_id",
Expand Down Expand Up @@ -2252,4 +2341,4 @@
}
],
"renames": []
}
}
1 change: 1 addition & 0 deletions packages/core/src/database/migration.gen.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Effect } from "effect"
import type { DatabaseMigration } from "../migration"

export default {
id: "20260706181957_add_instruction_file",
up(tx) {
return Effect.gen(function* () {
yield* tx.run(`
CREATE TABLE \`instruction_file\` (
\`session_id\` text NOT NULL,
\`path\` text NOT NULL,
\`content\` text NOT NULL,
\`message_seq\` integer NOT NULL,
\`discovered_seq\` integer NOT NULL,
\`position\` integer NOT NULL,
CONSTRAINT \`instruction_file_pk\` PRIMARY KEY(\`session_id\`, \`path\`),
CONSTRAINT \`fk_instruction_file_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE
);
`)
})
},
} satisfies DatabaseMigration.Migration
12 changes: 12 additions & 0 deletions packages/core/src/database/schema.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,18 @@ export default {
CONSTRAINT \`fk_instruction_entry_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE
);
`)
yield* tx.run(`
CREATE TABLE \`instruction_file\` (
\`session_id\` text NOT NULL,
\`path\` text NOT NULL,
\`content\` text NOT NULL,
\`message_seq\` integer NOT NULL,
\`discovered_seq\` integer NOT NULL,
\`position\` integer NOT NULL,
CONSTRAINT \`instruction_file_pk\` PRIMARY KEY(\`session_id\`, \`path\`),
CONSTRAINT \`fk_instruction_file_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE
);
`)
yield* tx.run(`
CREATE TABLE \`message\` (
\`id\` text PRIMARY KEY,
Expand Down
Loading
Loading