Upgrading from v0.84.0

Stop any running agnostic-ai watch process before updating the installation or project config.

Install through your existing package manager. For a global npm installation:

npm install -g agnostic-ai@0.85.0

For an exact project config pin, agnostic-ai upgrade --requires updates requires and the schema URL to the installed version, then syncs. It also replaces minimum or range requirements and local overrides. To keep a deliberate minimum or range, retain that value, update the schema URL to v0.85.0, review agnostic-ai migrate --dry-run, and run agnostic-ai sync. See upgrade behavior.

This release changes generated files for several tools, so sync --check reports drift until you run agnostic-ai sync. Review the diff, commit it, then run agnostic-ai sync --check and restart watch. The sections below say which projects see a change and why.

Permissions get stricter

OpenCode: an agent with a can or tools list now writes a permission map. Before, sync dropped the list without a note, so a reviewer meant to only read ran with OpenCode's base permissions. Now every tool you do not list is denied, and each listed tool keeps the project's ask and deny rules. A project allow never widens the agent. A restricted agent also asks before OpenCode's own temp and skill folders outside the project, which OpenCode allows by default, because those paths depend on the machine. Check each agent that has a list. To override the result for one agent, use x-opencode.permission on it. See OpenCode.

OpenCode: a broad deny or ask now wins over a narrower allow. OpenCode applies the last matching rule, and sync used to write each tool's patterns in alphabetical order. A git push * deny came before a git push origin * allow, so it blocked nothing. Patterns now go allow, then ask, then deny. The same spec behaves this way on Claude Code, Devin CLI, Augment and Kilo, and the old order was in place from v0.62.0 to v0.84.0. If you wrote ask: Bash(*) with allow: Bash(git status:*), git status used to run without asking. It now asks. Expect more prompts if you relied on "ask for everything except a few commands".

Kilo: a restricted agent gets exactly the stricter of the project's rules and its own list. Kilo applies an agent's rules after the project's, and the last match wins, so a listed tool used to override a project ask or deny for that tool. Now the project's rules apply inside what the agent allows. Three visible changes:

  • A bare Bash in an agent's list now asks, as Kilo itself does, and writes Kilo's read-only command allows (about 40 lines in the agent file). Before, it allowed every command.
  • A Write rule lands under edit, the permission Kilo's write tool checks, instead of an unused write key.
  • A restricted agent asks for paths outside the project and for doom_loop instead of denying them. It asks for directories Kilo allows outside the project, because that list depends on the machine.

A project bash: ask stays ask. See Kilo.

prefer-spec picks one winner

This applies only if you set sync.collision-policy: prefer-spec and two targets write the same path differently. Before, sync wrote every target in parallel, so whichever finished last won, and the winner changed between runs. sync --check and status compared the file against each target's own version, so they reported drift that no sync could clear. Now the file gets the version of the last target in targets: that writes it, and sync, sync --check and status agree. Reordering targets: changes the winner. -t does not, and --check --diff shows only the winning version. Sync prints a note naming each winning target and the targets it overrode, so you can check that the last writer is the one you want. See sync.collision-policy.

Rules and instruction files change once

Rules written with paths: now scope on every tool. Copilot used to write applyTo: "**" and Cursor alwaysApply: true for such a rule, so it loaded everywhere. It now loads only for the matching files, as it already did on Claude Code, Codex and nested files. validate and LINT013 reject a rule whose paths and globs name different patterns. The migration unit is one rule: keep one of the two fields. See rule fields.

Root instruction files get a one-time diff. When a path-scoped rule cannot become a nested file, sync inlines it into AGENTS.md, GEMINI.md or .junie/AGENTS.md. The section now states Applies to: \resources/js/**`under its heading, so it no longer reads as a repo-wide rule, and sync adds ascope: 1marker in the source comment. A project synced by v0.84.0 shows that diff once; after you commit it,sync --check` is clean. The line is left out for a catch-all glob.

Root instruction files drop the provenance header when every reader opts out. If every target that reads a root AGENTS.md, CLAUDE.md, GEMINI.md or .github/copilot-instructions.md sets outputs.<target>.provenance-header: false, sync used to write the "Generated by agnostic-ai" header into the file anyway. It no longer does. One reader that keeps the header keeps it in the file. The next sync removes the header from existing files, so commit that diff. doctor still counts these files as managed.

Copilot writes a VS Code setting

With Copilot and any root AGENTS.md target both on, sync writes the full instructions to .github/copilot-instructions.md and AGENTS.md, and VS Code's local chat applied both to every request. Sync now sets "chat.useAgentsMdFile": false in .vscode/settings.json, so the local chat loads the instructions once. VS Code reads this setting only for its local agent, and only in a trusted workspace. Commit the file.

  • A value you set yourself wins. If you keep it true, sync prints a note.
  • Turning the setting off also drops nested AGENTS.md files in the local chat. Copilot reads scoped rules from its own .instructions.md files.
  • Merging into a .vscode/settings.json that has comments drops them, with a one-time warning.
  • GitHub.com code review and the Copilot cloud agent still read both files and have no such setting. See Copilot.

Lint and handoff files

  • LINT047 is a warning for a skill or command name that Claude Code refuses to load, such as one with a zero-width character, < or >. lint --strict fails until you rename it. See lint codes.
  • With handoff on and Factory as a target, sync adds the shared handoff store to .factory/settings.local.json. Sync keeps the file out of Git.
  • Turning handoff off now removes its grant from .claude/settings.local.json and .qoder/settings.json in one sync, and deletes the file when the grant was all it held.

Refresh your Git hooks

The generated hooks now name the install for your package manager when agnostic-ai is missing: bun install --frozen-lockfile, pnpm install --frozen-lockfile, npm ci or yarn install. Run agnostic-ai install-hook again, with the flags you used before (--post-checkout, --shared), to update a hook you installed earlier. It replaces only the old missing-binary line in the pre-commit, post-checkout and post-merge hooks and leaves the rest of each file alone.

What agnostic-ai changed

Restrict an agent once and get the same limit on OpenCode and Kilo

A portable can list is the one place to say what an agent may do. This agent reads files and runs one Git command:

---
name: reviewer
description: Review a diff without editing
can: [read, shell(git diff *)]
---

On OpenCode the list becomes the agent's permission map with "*": deny first. Each listed tool then replays the project's rules inside what the list allows, and mcp:<server> allows only that server's tools. Kilo gets the same result in its own key names. Both are checked by a test that runs sync end to end against a copy of each tool's matching rules and fails if any agent decides looser than the project would.

Scope a rule once

paths: is another name for globs: everywhere:

---
name: frontend
paths: "resources/js/**"
---
Use the shared form components.

Copilot, Cursor and Claude Code load it only for those files. Where a tool cannot take a nested file, the inlined section says Applies to: and the path.

Give a VS Code MCP server its own sandbox

VS Code reads allow rules for an MCP server only from that server's sandbox object in .vscode/mcp.json. Sync now writes it for stdio servers from the MCP spec's top level (or x-copilot, which also carries cwd, envFile, sandboxEnabled, oauth and dev now):

name: builder
description: Build tools in a sandbox.
type: stdio
command: npx
args: ["-y", "example-build-server"]
sandboxEnabled: true
sandbox:
  filesystem:
    allowWrite: ["/tmp/build-cache"]
  network:
    allowedDomains: ["registry.example.com"]

The five keys are filesystem.allowWrite, filesystem.denyRead, filesystem.denyWrite, network.allowedDomains and network.deniedDomains. import copilot keeps them. .github/mcp.json stays on the plain schema.

Bootstrap bun projects

agnostic-ai project --bootstrap used to refuse a bun project, while the post-checkout hook told you to run it. It now reads the package manager from packageManager, devEngines.packageManager or the only committed lockfile. For bun it needs bun.lock or bun.lockb and runs bun install --frozen-lockfile. Any other manager gets a refusal that names its own install step. A malformed devEngines no longer blocks project or project --check. See project.

Smaller fixes

  • sync --keep-edits no longer keeps a skill file that Codex and Amp share as a hand edit after a branch switch. sync --check stays clean.
  • Codex agent files report service_tier as ignored, since Codex follows the session's tier.
  • import ellipsis keeps a reviewer without an environment in Ellipsis's basic sandbox. x-ellipsis.reviewer.environment: null does it by hand.
  • The note for a dropped disable-model-invocation on Factory and Crush names the outputs.<target>.skills-dir setting needed beside .agents/skills.

Full list: v0.85.0 release notes.

What changed in the targets

Devin CLI adds PreCompact and PostCompact hooks. The Devin CLI changelog for v3000.11.92, dated October 14, 2026 and checked October 15, says they run before and after context compaction, with manual and auto matchers, and that a failure does not block compaction. The windsurf target now writes both events to .devin/hooks.v1.json, and hook run accepts the two matchers. Devin documents no payload, so hook run needs --payload, and a block on either event is not counted. The handoff-pre-compact built-in stays off Devin until its payload and output routing are documented. See Windsurf / Devin.

OpenCode deprecates an agent's tools key in favor of permission. The OpenCode agents page, checked October 15, 2026, says tools is deprecated and to prefer the agent's permission field. Sync now writes that map from a can or tools list (see the upgrade section).

Copilot reads instruction files differently by product. The GitHub custom instructions table, checked October 15, 2026, lists only the repository-wide .github/copilot-instructions.md for Copilot Chat on GitHub.com. Visual Studio reads that file and path-specific files. The Copilot cloud agent and code review also read AGENTS.md, CLAUDE.md and GEMINI.md. The VS Code custom instructions page, checked the same day, says that for the Local harness, chat.useAgentsMdFile turns AGENTS.md support on or off, and the settings reference lists its default as true. Sync keeps the full text in .github/copilot-instructions.md for the products that read only it, and turns the setting off so VS Code's local chat does not load the same text twice. Other VS Code agent harnesses follow their own rules, and the setting does not change them.

Kilo applies the last matching rule, with the agent's rules after the project's. Kilo's permissions page, checked October 15, 2026, says the last matching rule wins and to put broad rules first. Kilo's agent source, read the same day, merges defaults, then the project's permission, then the agent's. That order is why a listed tool could override a project ask.

Claude Code refuses some skill and command names. The skills docs, checked October 15, 2026, list characters a name cannot hold, such as control and zero-width characters, < and >. Such a skill never loads, and lint now warns (LINT047).

Factory's sandbox limits writes to the working folder. The Factory sandbox page, checked October 15, 2026, says file writes are denied except the working directory unless sandbox.filesystem.allowWrite adds paths. From a linked worktree, saving a handoff writes to the main checkout, which the sandbox blocks. Sync adds the store to sandbox.filesystem.allowWrite in .factory/settings.local.json and never sets sandbox.enabled. This release has not verified whether that local list joins or replaces the one in .factory/settings.json, so check that a handoff saves from a linked worktree. See Factory.