@lawaty/lacode 0.5.0 → 0.7.0

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/dist/index.js CHANGED
@@ -611,8 +611,9 @@ function coolProvider(s, provider, until, reason) {
611
611
  return affected;
612
612
  }
613
613
 
614
- // src/lib/manager-directive.ts
615
- var MANAGER_AGENT_NAME = "manager";
614
+ // src/lib/agent-instructions.ts
615
+ var AGENT_INSTRUCTIONS_COMMAND = "agent-instructions";
616
+ var AGENT_INSTRUCTIONS_WRITER = "instructions";
616
617
 
617
618
  // src/agents.ts
618
619
  var POOLED_BASES = ["explore", "implement", "context"];
@@ -650,14 +651,28 @@ different number.
650
651
 
651
652
  The pooled agents are the ONLY route to investigation and implementation. If the
652
653
  pool cannot serve a spawn \u2014 every slot cooling or exhausted, spawns repeatedly
653
- failing, or a runtime message saying no slot is available \u2014 that is a STOP
654
- condition, not a reason to do the work yourself.
654
+ failing, or a runtime message saying no slot is available \u2014 that is not a reason
655
+ to do the work yourself, and not a reason to stop and ask.
656
+
657
+ **Retry.** A refused or cooling slot is transient and costs you nothing but a
658
+ turn. Spawn the bare base again. Do not escalate a \`-N\` variant when a refusal
659
+ names one \u2014 the refusal means the pool has a routing problem, not that you
660
+ picked the wrong number.
661
+
662
+ Retry is always available and never wrong, which is why it is the default. But
663
+ "never wrong" is not "sufficient": looping silently against a pool with every
664
+ model cooling goes nowhere and burns the slot doing it. So separate the two
665
+ failures. **Transient** \u2014 a cooldown, a rate limit, one slot at its ceiling \u2014
666
+ means retry. **Persistent or structural** \u2014 every slot cooling, the same spawn
667
+ failing repeatedly with the same error, a malformed model id \u2014 means stop
668
+ retrying and *report* it: say what failed (slot, model, error) and continue
669
+ with whatever else the task needs, or ask the user. Surface the failure; do not
670
+ spin on it and do not let it end the whole task.
655
671
 
656
672
  **Never fall back to reading, grepping, exploring or implementing on your own.**
657
- Do not "just quickly" inspect a file because a spawn failed. Stop, say what
658
- failed (slot, model, error), and ASK the user how to proceed: wait for a slot to
659
- recover, change the pool, or obtain explicit permission to work without
660
- subagents. A failed spawn is never permission, and silence is not consent.
673
+ Do not "just quickly" inspect a file because a spawn failed. A failed spawn is
674
+ never permission, and silence is not consent \u2014 that part does not change with
675
+ cooldowns, and no amount of retrying grants it.
661
676
 
662
677
  \`edit\`/\`write\`/\`bash\` stay yours for applying and verifying what a subagent
663
678
  returned \u2014 never as a substitute for a spawn that could not run.
@@ -736,7 +751,12 @@ missing). Never paste context file contents into the report.`,
736
751
  "edit": {
737
752
  "*": "allow",
738
753
  "*/.opencode/context/**": "deny",
739
- ".opencode/context/**": "deny"
754
+ ".opencode/context/**": "deny",
755
+ // AGENTS.md has exactly one writer, the hidden `instructions` agent.
756
+ // opencode resolves a file permission with findLast over the map's own
757
+ // entry order, so this deny has to come AFTER the broad "*" allow above.
758
+ "AGENTS.md": "deny",
759
+ "*/AGENTS.md": "deny"
740
760
  },
741
761
  "bash": "allow",
742
762
  "webfetch": "deny",
@@ -979,7 +999,11 @@ if the blocker is understanding rather than execution, report that instead.`,
979
999
  "edit": {
980
1000
  "*": "allow",
981
1001
  "*/.opencode/context/**": "deny",
982
- ".opencode/context/**": "deny"
1002
+ ".opencode/context/**": "deny",
1003
+ // AGENTS.md is written by the hidden `instructions` agent alone; LAST
1004
+ // match wins, so this deny must sit after the broad allow above.
1005
+ "AGENTS.md": "deny",
1006
+ "*/AGENTS.md": "deny"
983
1007
  },
984
1008
  "bash": "allow",
985
1009
  "webfetch": "allow",
@@ -1023,29 +1047,14 @@ You own exactly these five files and nothing else:
1023
1047
  during work that are not already recorded in the project's own decision
1024
1048
  log. Concise; variable length.
1025
1049
 
1026
- A sixth file sits in the same directory and is not yours:
1027
- \`.opencode/context/manager.md\`. It is the client's own statement of intent
1028
- \u2014 what is being worked on, what comes next, what they have settled, and
1029
- what every agent should keep in mind. It deliberately says nothing about
1030
- where code lives: your five files and the source itself are the only
1031
- authority on that, and this file never contradicts them. It has no fixed
1032
- schema \u2014 read the whole file, because every heading in it is direction.
1033
-
1034
- You never create, edit, rename, or delete it \u2014 not at bootstrap, not in an
1035
- update, not in a review, and not when a run of your own concludes the work
1036
- has moved on. The client edits it, or asks a live agent to edit it on
1037
- their explicit instruction. Either way it is their hand, never yours.
1038
-
1039
- Read it before you write anything. Its \`## Current\` and \`## Next\`
1040
- sections tell you what is actually being worked on, and \`## Confirmed\`
1041
- tells you which of your facts the client has ratified. A fact you are
1042
- writing that appears under \`## Confirmed\` may be stated plainly, without
1043
- a confidence marker; anything else follows your normal rules \u2014 infer
1044
- carefully, mark uncertainty. Never copy its content into the five files.
1045
-
1046
- A missing or empty section is not an instruction. It means the client has
1047
- not said, not that you may assume anything \u2014 proceed exactly as you would
1048
- without the file.
1050
+ # Current-state only
1051
+
1052
+ Every file you write states only the current arrangement and the reason it
1053
+ holds, in the present tense. No "used to", "previously", "before this",
1054
+ migration notes or deprecation narrative \u2014 history belongs in the project's
1055
+ changelog, not in your map. An absence that is true today is a fact worth
1056
+ stating, not a removal worth narrating. When a past state is worth keeping,
1057
+ record it briefly in \`changelog.md\` instead.
1049
1058
 
1050
1059
  Never create, modify, or delete anything outside \`.opencode/context/\`. The
1051
1060
  \`edit\` permission enforces this. Do not attempt to work around it with bash.
@@ -1081,11 +1090,6 @@ Then write the five files. For each significant subsystem, give a short
1081
1090
  reason. This is the single most valuable thing you produce: where an agent
1082
1091
  should open its editor next.
1083
1092
 
1084
- manager.md is created for the client by the plugin, not by you; if it is
1085
- missing anyway, mention once in your final report that they can add it
1086
- themselves to record what is being worked on, what comes next, and what
1087
- they have ratified. Never create it.
1088
-
1089
1093
  # Incremental update
1090
1094
 
1091
1095
  Trigger: \`.opencode/context/\` exists and work has just been done here.
@@ -1113,14 +1117,6 @@ that is already stated in another context file \u2014 one fact has one home, and
1113
1117
  the other files link to it. If nothing material changed, make no edits and
1114
1118
  report "no update needed".
1115
1119
 
1116
- Before editing, re-read manager.md: its \`## Current\` and \`## Next\`
1117
- sections tell you what the client is actually working on, and its
1118
- \`## Confirmed\` section settles which of your facts are ratified. If what
1119
- you are about to write would place the code somewhere the client never
1120
- described, trust the code, make the edit the code justifies, and report
1121
- the gap in your final message \u2014 never reconcile the two sides silently,
1122
- and never edit manager.md to close it.
1123
-
1124
1120
  # Minimal exploration
1125
1121
 
1126
1122
  Default shape:
@@ -1215,14 +1211,10 @@ Audit the five files for:
1215
1211
  - duplicated information \u2014 one canonical place per fact
1216
1212
  - missing canonical entry points for significant subsystems
1217
1213
  - unsupported assumptions \u2014 anything unmarked that you cannot verify
1218
- - manager.md, if present: is \`## Current\` and \`## Next\` still true of
1219
- recent work, is every \`## Confirmed\` entry still true of the code, has
1220
- it outgrown roughly 150 lines \u2014 report findings, but never edit, prune,
1221
- or reorganize it; that is the client's call
1222
1214
 
1223
- Fix problems only in the five files you own \u2014 never in manager.md, which
1224
- belongs to the client. Never modify source code during a review. Report
1225
- what you found, what you fixed, and what you could not verify.
1215
+ Fix problems only in the five files you own. Never modify source code
1216
+ during a review. Report what you found, what you fixed, and what you
1217
+ could not verify.
1226
1218
 
1227
1219
  # Reporting
1228
1220
 
@@ -1240,9 +1232,7 @@ Finish with a short report:
1240
1232
  "edit": {
1241
1233
  "*": "deny",
1242
1234
  "*/.opencode/context/**": "allow",
1243
- ".opencode/context/**": "allow",
1244
- "*/.opencode/context/manager.md": "deny",
1245
- ".opencode/context/manager.md": "deny"
1235
+ ".opencode/context/**": "allow"
1246
1236
  },
1247
1237
  "bash": {
1248
1238
  "*": "deny",
@@ -1290,58 +1280,60 @@ Finish with a short report:
1290
1280
  }
1291
1281
  }
1292
1282
  };
1293
- var MANAGER_AGENT = {
1294
- description: "Records and edits the client's .opencode/context/manager.md. Run only by the /manager-directive command; no agent or subagent can spawn it.",
1283
+ var INSTRUCTIONS_AGENT = {
1284
+ description: "Edits the project's AGENTS.md. Run only by the /agent-instructions command; no agent or subagent can spawn it.",
1295
1285
  mode: "subagent",
1296
1286
  hidden: true,
1297
1287
  temperature: 0.1,
1298
1288
  prompt: `# Role
1299
1289
 
1300
- You maintain one file and nothing else: \`.opencode/context/manager.md\`, the
1301
- client's own statement of intent. You are not a coding agent and you touch no
1302
- other path.
1290
+ You maintain one file and nothing else: the project's \`AGENTS.md\`. You are not a
1291
+ coding agent and you touch no other path.
1303
1292
 
1304
- You are run only by the \`/manager-directive\` command. The client tells you what
1293
+ You are run only by the \`/agent-instructions\` command. The client tells you what
1305
1294
  they want recorded or changed in the file; you apply that to the file and report
1306
1295
  what you changed. You have no permission to edit anything else, and you need
1307
1296
  none.
1308
1297
 
1309
1298
  # The file
1310
1299
 
1311
- It records what is being worked on (\`## Current\`), what comes next
1312
- (\`## Next\`), what the client has ratified (\`## Confirmed\`), and standing
1313
- direction (\`## Instructions\`). The client may use any headings \u2014 every heading
1314
- is direction, and the four above are a convenience, not a schema.
1300
+ \`AGENTS.md\` is the project's standing instructions \u2014 the rules every agent and
1301
+ subagent runs under. opencode loads it into every session automatically, so what
1302
+ you write here steers all work in this project. Keep it about how to work:
1303
+ conventions, constraints, priorities, things to always do and never do. It says
1304
+ nothing about where code lives \u2014 the source and the context map are the authority
1305
+ on that.
1315
1306
 
1316
1307
  # How to apply a directive
1317
1308
 
1318
- - Do what the client asked. "Append", "rewrite Current", "move X to Confirmed",
1319
- "add a heading" all mean exactly that; a bare sentence goes under the most
1320
- fitting existing heading, and you create one only if none fits.
1309
+ - Do what the client asked: add, rewrite, move or remove exactly what they asked
1310
+ for. A bare sentence goes under the most fitting existing heading, and you
1311
+ create a heading only if none fits.
1321
1312
  - Never invent facts, never record your own inference as the client's, and never
1322
1313
  tidy, reorder or delete content the client did not ask you to touch.
1323
- - \`## Current\` is rewritten, not appended to, so it does not become a running
1324
- history.
1314
+ - Prefer current-state wording: state how things are, not how they changed.
1325
1315
  - Keep the file concise. If it is growing past roughly 150 lines, say so.
1316
+ - If \`AGENTS.md\` does not exist, stop and report that there is nothing to edit.
1317
+ Do not create it.
1326
1318
 
1327
1319
  # Reporting
1328
1320
 
1329
1321
  Report briefly what you changed and where. Do not edit any other file.`,
1330
1322
  permission: {
1331
- // Read is scoped to the one file too: the directive is about manager.md, and
1323
+ // Read is scoped to the one file too: the directive is about AGENTS.md, and
1332
1324
  // nothing else is any of this agent's business.
1333
1325
  read: {
1334
1326
  "*": "deny",
1335
- ".opencode/context/manager.md": "allow",
1336
- "*/.opencode/context/manager.md": "allow"
1327
+ "AGENTS.md": "allow",
1328
+ "*/AGENTS.md": "allow"
1337
1329
  },
1338
1330
  glob: "deny",
1339
1331
  grep: "deny",
1340
1332
  list: "deny",
1341
1333
  edit: {
1342
1334
  "*": "deny",
1343
- ".opencode/context/manager.md": "allow",
1344
- "*/.opencode/context/manager.md": "allow"
1335
+ "AGENTS.md": "allow",
1336
+ "*/AGENTS.md": "allow"
1345
1337
  },
1346
1338
  bash: "deny",
1347
1339
  webfetch: "deny",
@@ -1367,7 +1359,7 @@ function buildAgentSet() {
1367
1359
  set[`${base}-${slot}`] = variant;
1368
1360
  }
1369
1361
  }
1370
- set[MANAGER_AGENT_NAME] = MANAGER_AGENT;
1362
+ set[AGENT_INSTRUCTIONS_WRITER] = INSTRUCTIONS_AGENT;
1371
1363
  return set;
1372
1364
  }
1373
1365
  function applyAgents(cfg, agents = buildAgentSet(), opts = {}) {
@@ -1407,13 +1399,7 @@ Remember: write conclusions, not inventories. Link to the project's existing
1407
1399
  documentation instead of duplicating it.
1408
1400
 
1409
1401
  Report what you created or updated, what you deliberately left out, and
1410
- anything that contradicts the code or existing docs.
1411
-
1412
- If \`.opencode/context/manager.md\` does not exist, mention in your final
1413
- report that the client can add it themselves \u2014 their own file with
1414
- \`## Current\`, \`## Next\`, \`## Confirmed\` and \`## Instructions\` \u2014 for what
1415
- is being worked on, what comes next, what they have ratified, and standing
1416
- direction. Never create it.`
1402
+ anything that contradicts the code or existing docs.`
1417
1403
  },
1418
1404
  "context-update": {
1419
1405
  description: "Incrementally update .opencode/context/ after recent work via the context agent.",
@@ -1444,9 +1430,8 @@ timestamp-only edits. If nothing material changed, make no edits and report
1444
1430
  subtask: true,
1445
1431
  template: `Context review.
1446
1432
 
1447
- Everything outside the five context files is read-only for this run \u2014
1448
- including \`manager.md\`, which belongs to the client. Do not modify source
1449
- code under any circumstances.
1433
+ Everything outside the five context files is read-only for this run. Do not
1434
+ modify source code under any circumstances.
1450
1435
 
1451
1436
  Audit the five context files for:
1452
1437
 
@@ -1459,18 +1444,15 @@ Audit the five context files for:
1459
1444
  - missing canonical entry points for significant subsystems
1460
1445
  - unsupported assumptions \u2014 anything stated as fact that you cannot verify,
1461
1446
  or that lacks a confidence marker
1462
- - \`manager.md\`, if present: is \`## Current\` and \`## Next\` still true of
1463
- recent work, is every \`## Confirmed\` entry still true of the code, has it
1464
- outgrown roughly 150 lines \u2014 report findings, but never edit it
1465
1447
 
1466
1448
  Fix what you find in \`.opencode/context/\` only, then report: findings, fixes,
1467
1449
  and anything you could not verify.`
1468
1450
  },
1469
- "manager-directive": {
1470
- description: "Apply a client instruction to .opencode/context/manager.md. Client-only \u2014 runs the manager agent, the only writer of that file.",
1471
- agent: MANAGER_AGENT_NAME,
1451
+ [AGENT_INSTRUCTIONS_COMMAND]: {
1452
+ description: "Apply a client instruction to the project's AGENTS.md. Client-only \u2014 runs the instructions agent, the only writer of that file.",
1453
+ agent: AGENT_INSTRUCTIONS_WRITER,
1472
1454
  subtask: true,
1473
- template: `Apply this instruction to \`.opencode/context/manager.md\`, and edit only that file:
1455
+ template: `Apply this instruction to the project's \`AGENTS.md\`, and edit only that file:
1474
1456
 
1475
1457
  $ARGUMENTS
1476
1458
 
@@ -1506,6 +1488,36 @@ Print one PASS/FAIL line per check below, with the exact fix for any FAIL.
1506
1488
  whether or not the gateway advertises it, so it needs no allowlist entry.
1507
1489
 
1508
1490
  Change nothing. Print a final one-line summary of failures.`
1491
+ },
1492
+ "pool": {
1493
+ description: "Modify this machine's LaCode pool from a short instruction \u2014 the shared free-model slot table in ~/.config/lacode/pool.txt. Restarts opencode afterwards.",
1494
+ template: `Apply this change to the LaCode pool on this machine:
1495
+
1496
+ $ARGUMENTS
1497
+
1498
+ The pool is ONE global slot table shared by every pooled base (explore, implement, context) \u2014 there are no per-base model lists, so "put X on explore" means "give X a slot", not a per-base override.
1499
+
1500
+ 1. Establish the baseline. Read \`${USER_MODELS_TXT}\`. If it is absent, the pool is resolving from the bundled preset \`presets/free-tier.json\`; read that file to learn what is in effect. Call the \`pool_status\` tool only if you need live load or cooldown state.
1501
+
1502
+ 2. Resolve the instruction above into a target slot table. These are the rules the loader enforces \u2014 never write a file that breaks one:
1503
+ - one slot per line: \`<provider>/<model-id> [weight]\`
1504
+ - at most ${MAX_SLOTS} slots, and a model may appear only once
1505
+ - weight is optional (default 1) and must be a number in (0, ${MAX_WEIGHT}]. It is the soft ceiling on concurrent claims and the slot's share of the rotation \u2014 NOT a priority; pick order follows line order.
1506
+ - \`#\` starts a comment (whole-line or trailing); blank lines are ignored.
1507
+ If the instruction names a model ambiguously, or would need more than ${MAX_SLOTS} slots, stop and ask rather than guessing.
1508
+
1509
+ 3. Write the WHOLE file, not a patch. This file is an override, not an edit target: any slot you drop disappears, and slot numbers are line positions, so a partial write silently renumbers the rotation. Keep the existing comment header. If the write fails on a missing directory, create \`~/.config/lacode\` first and retry.
1510
+
1511
+ 4. Report the before \u2192 after slot table, the resolved path, and this reminder in substance: nothing hot-reloads, so every running opencode process must be restarted before the new pool takes effect.
1512
+
1513
+ Two traps that fail silently, so check and state them explicitly:
1514
+ - A slot's provider must already exist in the user's opencode config, or that slot cannot resolve at all. If the instruction adds a model on a provider that is not configured, say so.
1515
+ - If a slot model is \`omniroute/<id>\`, that id must also appear in the plugin's \`omniroute.models\` allowlist (or be the \`combo\` id, which needs no entry) \u2014 otherwise the pool resolves and every spawn fails with \`ProviderModelNotFoundError\`.
1516
+ - A provider \`whitelist\` is an allowlist, and the plugin appends your model to it at config time. Nothing for you to do there.
1517
+
1518
+ If the instruction is to RESET or REVERT rather than to change models, delete \`${USER_MODELS_TXT}\` instead, and report that the pool falls back to the bundled preset \u2014 with the same restart reminder.
1519
+
1520
+ Change nothing else. In particular do not touch \`presets/free-tier.json\`, \`~/.config/lacode/pool.json\`, \`FALLBACK_SLOTS\` in \`src/lib/pool.ts\`, or \`tests/models-snapshot.json\`: this command owns the per-machine override and nothing else.`
1509
1521
  }
1510
1522
  };
1511
1523
  function applyCommands(cfg, commands = COMMANDS) {
@@ -1522,45 +1534,6 @@ function applyCommands(cfg, commands = COMMANDS) {
1522
1534
  }
1523
1535
  return { added, kept };
1524
1536
  }
1525
- var INSTRUCTION_MARKER = "<!-- lacode:context-map-instruction:v1 -->";
1526
- var INSTRUCTION_OPT_OUT = "<!-- lacode:context-map-instruction:off -->";
1527
- var STANDING_INSTRUCTION = `## Repository context map
1528
-
1529
- This project may keep a navigation map in \`.opencode/context/\`. Before broad
1530
- exploration, check whether it exists (\`ls .opencode/context\` \u2014 never the \`glob\`
1531
- tool, which skips hidden directories). If \`manager.md\` exists there, read it
1532
- first: it is the client's own statement of intent \u2014 what is being worked on,
1533
- what comes next, \`## Confirmed\` lists what the client has ratified, and
1534
- \`## Instructions\` holds standing managerial directions. It outranks every
1535
- other context file and every inference of yours about what matters right now.
1536
- It says nothing about where code lives, so it cannot contradict the code;
1537
- treat its \`## Confirmed\` entries as settled decisions, not as a licence to
1538
- skip reading the code. Any heading in it is direction, so read the whole
1539
- file rather than only the sections above. The rest of the map remains usable,
1540
- just unratified where \`## Confirmed\` does not cover it. Then read only the
1541
- file relevant to the task \u2014 \`architecture.md\`, \`contexts.md\`,
1542
- \`conventions.md\`, \`workflows.md\`, \`decisions.md\` \u2014 and start from the
1543
- canonical entry points it lists.
1544
-
1545
- Source code is authoritative: if the map disagrees with the code,
1546
- trust the code and say so; never edit source to match it.
1547
- Never edit the five context files yourself \u2014 the context agent owns them.
1548
- \`manager.md\` is the client's own file and the context agent is explicitly
1549
- permission-denied from writing it. You may write it only when the client
1550
- explicitly asks you to in this conversation, and then only what they asked
1551
- for; never on your own initiative, and never to "keep it up to date". Say in
1552
- your final report if your work revealed something that belongs to the map, or
1553
- if \`manager.md\` and the code disagree.`;
1554
- function applyInstructions(cfg) {
1555
- const existing = Array.isArray(cfg.instructions) ? cfg.instructions : [];
1556
- const texts = existing.filter((e) => typeof e === "string");
1557
- if (texts.some((e) => e.includes(INSTRUCTION_OPT_OUT))) return { added: false };
1558
- if (texts.some((e) => e.includes(INSTRUCTION_MARKER))) return { added: false };
1559
- cfg.instructions = [...existing, `${INSTRUCTION_MARKER}
1560
-
1561
- ${STANDING_INSTRUCTION}`];
1562
- return { added: true };
1563
- }
1564
1537
 
1565
1538
  // src/plugins/agent-pool.ts
1566
1539
  import { tool } from "@opencode-ai/plugin";
@@ -1896,7 +1869,7 @@ round robin in slot order, each slot taking as many turns as its weight says, so
1896
1869
  });
1897
1870
 
1898
1871
  // src/plugins/context-autoupdate.ts
1899
- import { existsSync as existsSync2, readdirSync as readdirSync2, statSync as statSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
1872
+ import { existsSync as existsSync2, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
1900
1873
  import * as path2 from "node:path";
1901
1874
 
1902
1875
  // src/lib/jsonc.ts
@@ -1951,7 +1924,7 @@ import { readFileSync as readFileSync3 } from "node:fs";
1951
1924
  import * as path from "node:path";
1952
1925
  var CONTEXT_DIR = path.join(".opencode", "context");
1953
1926
  var WRITER = "context";
1954
- var MANAGER_WRITER = MANAGER_AGENT_NAME;
1927
+ var INSTRUCTIONS_WRITER = AGENT_INSTRUCTIONS_WRITER;
1955
1928
  var toPosix = (value) => value.split(path.sep).join("/");
1956
1929
  var compilePattern = (pattern) => {
1957
1930
  const escaped = toPosix(pattern).replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
@@ -1980,8 +1953,8 @@ var evaluatedForm = (mapDir, projectRoot) => {
1980
1953
  const absolute = toPosix(path.join(mapDir, "architecture.md"));
1981
1954
  return projectRoot ? toPosix(path.relative(projectRoot, absolute)) : absolute;
1982
1955
  };
1983
- var managerForm = (mapDir, projectRoot) => {
1984
- const absolute = toPosix(path.join(mapDir, "manager.md"));
1956
+ var agentsForm = (mapDir, projectRoot) => {
1957
+ const absolute = toPosix(path.join(mapDir, "..", "..", "AGENTS.md"));
1985
1958
  return projectRoot ? toPosix(path.relative(projectRoot, absolute)) : absolute;
1986
1959
  };
1987
1960
  var verifyWriterRule = (configPath, mapDir, projectRoot) => {
@@ -2015,17 +1988,17 @@ var verifyWriterRule = (configPath, mapDir, projectRoot) => {
2015
1988
  return `context map has more than one writer: ${offenders.join(", ")} would be granted the map by permission, evaluating "${form}". Only ${WRITER} may write the map. Narrow the grant and put the deny LAST -- opencode takes the LAST matching rule, so "${CONTEXT_DIR}/**": "deny" written after "*": "allow" is what denies it: "*": "allow", "*/${CONTEXT_DIR}/**": "deny", "${CONTEXT_DIR}/**": "deny". Both spellings are required because the evaluated path depends on the project root.`;
2016
1989
  }
2017
1990
  }
2018
- const managerPath = managerForm(mapDir, projectRoot);
1991
+ const agentsPath = agentsForm(mapDir, projectRoot);
2019
1992
  const agentDefs = readAgents(raw);
2020
1993
  if (agentDefs) {
2021
1994
  const writers = [];
2022
1995
  for (const [name, def] of Object.entries(agentDefs)) {
2023
- if (name === MANAGER_WRITER) continue;
2024
- const win = winningRule(permissionOf(def), managerPath);
1996
+ if (name === INSTRUCTIONS_WRITER) continue;
1997
+ const win = winningRule(permissionOf(def), agentsPath);
2025
1998
  if (win?.action === "allow") writers.push(`${name} (edit rule "${win.pattern}": "${win.action}")`);
2026
1999
  }
2027
2000
  if (writers.length > 0) {
2028
- return `${CONTEXT_DIR}/manager.md is writable by permission: ${writers.join(", ")}. It is the client's own file \u2014 what they are working on, what is ratified, what every agent must respect \u2014 and only the \`${MANAGER_WRITER}\` agent (run solely by /manager-directive) may write it. Deny it LAST on every other agent, after any broad allow, because opencode takes the LAST matching rule: "*": "allow", "*/${CONTEXT_DIR}/manager.md": "deny", "${CONTEXT_DIR}/manager.md": "deny". Declare this on every agent above, including \`${WRITER}\`: an agent you define yourself replaces the shipped one wholesale, permission and all.`;
2001
+ return `AGENTS.md is writable by permission: ${writers.join(", ")}. It is the project's own file \u2014 the standing instructions every agent runs under \u2014 and only the \`${INSTRUCTIONS_WRITER}\` agent (run solely by /agent-instructions) may write it. Deny it LAST on every other agent, after any broad allow, because opencode takes the LAST matching rule: "*": "allow", "AGENTS.md": "deny", "*/AGENTS.md": "deny". Declare this on every agent above, including \`${WRITER}\`: an agent you define yourself replaces the shipped one wholesale, permission and all.`;
2029
2002
  }
2030
2003
  }
2031
2004
  return void 0;
@@ -2054,51 +2027,6 @@ var IGNORED_SEGMENTS = /* @__PURE__ */ new Set([
2054
2027
  ".cache",
2055
2028
  ".git"
2056
2029
  ]);
2057
- var MANAGER_TEMPLATE = `# Managerial directions
2058
-
2059
- This file is yours. No agent writes it: the context agent is explicitly denied
2060
- permission to touch this path, and nothing changes it except you, or an agent
2061
- acting on your explicit instruction in that conversation.
2062
-
2063
- It records what you want done and how you want it approached \u2014 what is being
2064
- worked on, what comes next, what you have settled, and what every agent should
2065
- keep in mind. It deliberately says nothing about where code lives: the source
2066
- and the five generated context files are the only authority on that, so this
2067
- file can never contradict the code.
2068
-
2069
- Add any headings you like. The four below are a convenience, not a schema \u2014
2070
- every heading in this file is direction.
2071
-
2072
- ## Current
2073
-
2074
- <!-- What is being worked on right now. Rewrite it; do not append a history. -->
2075
-
2076
- ## Next
2077
-
2078
- <!-- What comes next, in order. -->
2079
-
2080
- ## Confirmed
2081
-
2082
- <!-- What you have personally ratified. Nothing enters or leaves this list
2083
- except by your hand \u2014 no agent promotes, prunes or rewrites it. -->
2084
-
2085
- ## Instructions
2086
-
2087
- <!-- Standing direction that applies beyond the current task: priorities, things
2088
- to care about, constraints that are not obvious from the code. -->`;
2089
- var ensureManagerFile = (root) => {
2090
- try {
2091
- const target = path2.join(root, ".opencode", "context", "manager.md");
2092
- if (existsSync2(target)) return { created: false };
2093
- mkdirSync2(path2.dirname(target), { recursive: true });
2094
- writeFileSync2(target, MANAGER_TEMPLATE, { flag: "wx" });
2095
- return { created: true };
2096
- } catch (error) {
2097
- if (error?.code === "EEXIST") return { created: false };
2098
- console.warn(`[context-autoupdate] ensureManagerFile failed: ${error}`);
2099
- return { created: false };
2100
- }
2101
- };
2102
2030
  var toPosix2 = (value) => value.split(path2.sep).join("/");
2103
2031
  var findProjectConfig = () => {
2104
2032
  let dir = import.meta.dir ?? path2.dirname(new URL(import.meta.url).pathname);
@@ -2142,7 +2070,6 @@ var contextAutoUpdateHooks = (async ({ client, directory }, options) => {
2142
2070
  });
2143
2071
  const root = path2.resolve(directory);
2144
2072
  const contextAbs = path2.join(root, CONTEXT_DIR2);
2145
- if (ensureManagerFile(root).created) void log("info", `created ${CONTEXT_DIR2}/manager.md`);
2146
2073
  const config = findProjectConfig();
2147
2074
  const writerProblem = config ? verifyWriterRule(config, contextAbs, root) : void 0;
2148
2075
  if (writerProblem) void log("error", writerProblem);
@@ -3102,7 +3029,7 @@ var omniRouteHooks = async (input, options, deps = {}) => {
3102
3029
 
3103
3030
  // src/lib/selfupdate.ts
3104
3031
  import { spawn as spawn2 } from "node:child_process";
3105
- import { closeSync, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync4, renameSync as renameSync2, rmSync, statSync as statSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3, writeSync } from "node:fs";
3032
+ import { closeSync, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync4, renameSync as renameSync2, rmSync, statSync as statSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2, writeSync } from "node:fs";
3106
3033
  import { homedir as homedir2 } from "node:os";
3107
3034
  import { dirname as dirname3, join as join6, resolve as resolve2 } from "node:path";
3108
3035
  var REGISTRY_LATEST = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
@@ -3196,8 +3123,8 @@ function readState(path4 = STATE_PATH) {
3196
3123
  }
3197
3124
  function writeState(state2, path4 = STATE_PATH) {
3198
3125
  try {
3199
- mkdirSync3(dirname3(path4), { recursive: true });
3200
- writeFileSync3(path4, JSON.stringify(state2));
3126
+ mkdirSync2(dirname3(path4), { recursive: true });
3127
+ writeFileSync2(path4, JSON.stringify(state2));
3201
3128
  } catch {
3202
3129
  }
3203
3130
  }
@@ -3223,7 +3150,7 @@ function acquireLock(path4 = LOCK_PATH, now = Date.now()) {
3223
3150
  };
3224
3151
  };
3225
3152
  try {
3226
- mkdirSync3(dirname3(path4), { recursive: true });
3153
+ mkdirSync2(dirname3(path4), { recursive: true });
3227
3154
  return claim();
3228
3155
  } catch {
3229
3156
  let orphaned = false;
@@ -3411,9 +3338,6 @@ var LaCode = (async (input, options) => {
3411
3338
  if (cmds.added.length > 0) {
3412
3339
  await log("info", `commands: added ${cmds.added.join(", ")}; kept ${cmds.kept.join(", ") || "none"} already defined`);
3413
3340
  }
3414
- if (applyInstructions(cfg).added) {
3415
- await log("info", "instructions: ensured the standing context-map rule is present");
3416
- }
3417
3341
  await omniroute.config?.(cfg);
3418
3342
  await pool.config?.(cfg);
3419
3343
  } catch (error) {
@@ -88,10 +88,9 @@ never priced at 0 and never priced at a guess. If you name such a model
88
88
  explicitly with `--model` / `--baseline-model`, the run exits non-zero and tells
89
89
  you to refresh or to pass `--allow-unknown`.
90
90
 
91
- This is the reason the results table below is empty. The pinned snapshot covers
92
- the bundled free preset only; the default baseline model is not in it, so the
93
- default offline run cannot produce an honest ratio. That is the harness working
94
- as designed.
91
+ This is why the results table below is empty. The pinned snapshot covers the
92
+ bundled free preset only; the default baseline model is not in it, so the
93
+ default offline run cannot produce an honest ratio.
95
94
 
96
95
  ## Results
97
96
 
@@ -116,11 +115,10 @@ harness prints `unknown`.
116
115
  `--out docs/BENCHMARKS.md` and exits 2.
117
116
 
118
117
  That refusal is the point. This file ships inside the npm tarball (`files`
119
- includes `docs`). A generated table dropped on top of it would replace the
120
- explanation with a dated artifact that reads as a published measurement of the
121
- package, and it would outlive the machine and the day that produced it. So the
122
- hand-written explainer is protected, and the generated output — which carries a
123
- footer pointing back here — goes to its own gitignored filename.
118
+ includes `docs`) and is the hand-written explainer. A generated table is a
119
+ measurement of one machine on one day, not a claim about the package, so the
120
+ explainer is protected and the generated output — which carries a footer
121
+ pointing back here — goes to its own gitignored filename.
124
122
 
125
123
  ```bash
126
124
  npm run benchmark -- --out docs/BENCHMARKS.generated.md
@@ -43,10 +43,10 @@ writes the context map and has no business in a browser.
43
43
  opencode folds an agent's `tools` into its permission list **at config-load
44
44
  time**, while decoding the config — before any plugin runs. A plugin's `config`
45
45
  hook mutates the already-decoded config, so the fold never re-runs and anything
46
- it puts in `agent.tools` is inert. (Verified on opencode 1.18.34/1.18.35 with
47
- `opencode debug agent explore`: a grant written in your own config shows two
48
- `playwright_*` entries — `deny` then `allow`, last one winning — while the same
49
- grant injected by the plugin shows only the `deny`.) LaCode's other injected
46
+ it puts in `agent.tools` is inert. On opencode 1.18.34/1.18.35, a grant
47
+ written in your own config shows two `playwright_*` entries — `deny` then
48
+ `allow`, last one winning — while the same grant injected by the plugin shows
49
+ only the `deny`. LaCode's other injected
50
50
  fields are not affected; `permission`, `prompt`, `model`, `description`,
51
51
  `temperature`, `mode` and `hidden` are all read after the plugin hook runs.
52
52
 
@@ -78,8 +78,8 @@ process.
78
78
  **18 agent keys**: the 5 bases `build`, `plan`, `explore`, `implement`,
79
79
  `context`, plus one hidden
80
80
  `<base>-1`..`-4` pool variant for each of the 3 pooled bases, plus the hidden
81
- `manager` agent — the one writer of `.opencode/context/manager.md`, reachable
82
- only from the `/manager-directive` command.
81
+ `instructions` agent — the one writer of the project's root `AGENTS.md`,
82
+ reachable only from the `/agent-instructions` command.
83
83
 
84
84
  `build` and `plan` exist in opencode as built-ins, so on a stock config those
85
85
  two keys are already taken and merge-without-clobber keeps the built-in — the
@@ -92,13 +92,13 @@ duplicate of `plan` apart from a pinned model, and `plan` is injected instead.
92
92
  description — a package cannot ship someone else's provider, quota or benchmark
93
93
  results — though its escalation ladder still resolves, because the two deep
94
94
  tiers it escalates to *are* injected. And `explore`, `general` and `implement`
95
- are only `{ "disable": true }` stubs in the author's own config: turning off
96
- opencode's built-in agents is a decision about one person's configuration, not
97
- a default a package should impose on a stranger.
95
+ are only `{ "disable": true }` stubs: turning off opencode's built-in agents
96
+ is a decision about one person's configuration, not a default a package should
97
+ impose on a stranger.
98
98
 
99
- One **field** is deliberately not injected either: `tools`, for the
100
- load-time-folding reason explained above. Nothing else the plugin writes into
101
- an agent is subject to it.
99
+ One **field** is deliberately not injected: `tools`, for the load-time-folding
100
+ reason explained above. Nothing else the plugin writes into an agent is subject
101
+ to it.
102
102
 
103
103
  **Installation merges, it does not clobber** (US-16). An agent, command or
104
104
  instruction is added only when that key is absent from your config. A