agnostic-ai v0.85.0: agents with a tools list get exact permissions on OpenCode and Kilo Agnostic-ai released v0.85.0, which makes an agent's `can` or `tools` list write an exact `permission` map on OpenCode and Kilo so every unlisted tool is denied, and changes rule ordering so a broad `deny` or `ask` now wins over a narrower `allow`. The release also fixes `sync.collision-policy: prefer-spec` so the last target in `targets:` that writes a path wins deterministically, and it changes generated files, so `sync --check` reports drift until users run `agnostic-ai sync`. Users upgrading from v0.84.0 must stop any running `agnostic-ai watch` process before updating. 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 https://agnostic-ai.org/docs/cli-reference/maintain/ upgrade . 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 https://agnostic-ai.org/docs/targets/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 https://agnostic-ai.org/docs/targets/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. Check that the last writer is the target you want. See sync.collision-policy https://agnostic-ai.org/docs/configuration/ synccollision-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 https://agnostic-ai.org/docs/spec-format/rules/ 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 a scope: 1 marker 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.