You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Intent installs on Linux through Homebrew (ST0081). On Homebrew on Linux, brew install matthewsinclair/intent/intent installs the release's Linux package for the machine's architecture, x86_64 or aarch64: intent and intentd built static against musl, with the support tree, and no checkout of Intent's source. docs/install.md#linux carries the steps.
intent issues --project <project> files and reads issues in another registered project (issue 0590). Every issues verb took its project from the working directory, so filing into another estate meant changing into it first. --project, given before the verb (intent issues --project Lamplight add "..."), names a project from the machine's registry (~/.config/intent/projects.json) by its root, its project_id, its directory name or its project_name, the last two case-insensitive. A value is read as a path only when it has a / in it, so a bare name that is also a directory under the working directory stays a name. A name two projects carry is refused naming both, a name none carries is refused listing the registry, and nothing falls back to the working directory's project. The answer names the project and its root, on stderr for list and show, and show --format json carries them as project and root.
A project chooses where its two agent contracts live: contracts: root or contracts: dotclaude (ST0083). root, the default, keeps AGENTS.md and CLAUDE.md at the project root, where the agents.md spec's readers open them. dotclaude keeps both in .claude/, which Claude Code reads natively, for a tree whose root is read by people rather than tools, such as a book or a shared estate. The key sits in intent/.config/config.json; absent means root, and no existing config changes. intent init --contracts dotclaude sets it at birth, and intent agents layout <root|dotclaude> moves an existing project's contracts and writes the key: it moves tracked files through git, refuses before moving anything when the destination holds a different file, and removes a usage-rules.md byte-identical to its seed on the way to dotclaude, which seeds none. intent agents sync, intent agents validate, intent claude upgrade --apply, intent doctor, the sync scope and the daemon's watch all read the key.
intent deinit strips what Intent wrote from a project being closed (ST0083). It is a dry run unless --apply is given: it lists each file it would remove or edit and each it keeps, with the reason, and writes nothing. With --apply it removes the generated contracts in either layout (a CLAUDE.md only while its user block is empty), a usage-rules.md and a .intent_critic.yml byte-identical to their seeds, and Intent's chain blocks in the git hooks with their carriers, keeping every other line of a hook; it removes from .claude/settings.json only the hook entries that run intent claude hook and the two deny rules the template adds, and from .mcp.json only the intent server, deleting either file when nothing else is left in it. A file it cannot prove Intent wrote, or cannot parse, is kept and named. --all also removes intent/ with the store and the project's row in the machine's project registry, and refuses while intentd watches the tree.
A store under a Dropbox folder is marked ignored for the Dropbox client (ST0083). When a project sits under a Dropbox folder, the first store open that creates intent/.cache, which intent init does and so does the first command in a fresh clone, marks the directory before the store file exists in it: com.apple.fileprovider.ignore#P and com.dropbox.ignored on macOS, user.com.dropbox.ignored on Linux. It says so once, on stdout from init and on stderr from any other command. The folder is read from the client's ~/.dropbox/info.json and matched on resolved paths, so a project reached through the ~/Dropbox symlink is found. A mark that fails is a warning with the command that sets it, and never fails the command. intent doctor shows, without counting it, an unmarked intent/.cache under Dropbox, with the command that marks it.
intent doctor reports four more things about a project's agent wiring (ST0083). It counts a contract Intent generated that sits in both layouts, naming both paths and the command that removes the stray copy; a .claude/CLAUDE.md a person wrote in a root project is not counted. It shows, without counting them, a .claude/settings.json Intent does not manage whose hook command names a path that does not exist on the machine; an author that is empty or reads Author Unknown; and a .claude/scripts/*.sh that names Intent in its header and that no hook command runs, which v2 wrote into every project and v3 reads none of, each with the command that removes it.
Fixed
intent daemon start --at-login and intent daemon stop --at-login refuse off macOS before writing anything (ST0081). Enrolment at login is a macOS LaunchAgent, and on Linux the start form left a ~/Library/LaunchAgents plist that nothing reads. Both forms now refuse, naming enrolment at login as macOS only and intent daemon start without the flag as the way to run the daemon.
The release's Homebrew smoke reads the prompt gate's refusal as the pass (issue 0600). The hook arm of bin/int brew smoke expected intent claude hook require-in-session to answer 0, which the gate does only where an earlier /in-session left a sentinel in /tmp/intent, so the arm passed at every cut on a Mac that had one and went red on a fresh machine, where the gate refused correctly. It now drives the gate with a prompt under a session id no sentinel exists for and passes on the refusal, exit 2 with the gate's own Expected sentinel: line, as bin/int linux smoke already did.
intent claude upgrade --apply no longer wires a prompt gate that nothing on the machine can release (issue 0601). The .claude/settings.json it writes blocks a Claude Code session's first prompt until /in-session runs, and nothing on the install path put the in-session skill on the machine, so a fresh user's first session was locked with no way out from inside it. The run now installs in-session under ~/.claude/skills/ before it writes the settings, and reports it on its own line; --skip-settings installs nothing, and an installed in-session without its release script is held, not overwritten. Where the skill is still missing, the gate lets every prompt through and says so once per session, naming intent claude skills install in-session, and intent doctor gives the same advice without counting it as a finding.
A write to a thread whose Objective or Context holds an H2 line of its own is no longer refused as a hand edit (issue 0588). Reading the cover back started a new section at every ## line, so a field holding one read back as only the text above it. An unedited cover then tripped a false CoverEditNotCarried on every write that renders it, the author's own intent set included, and the remedy it named, intent sync --to-store, would have cut the field at that heading. A heading the stored field holds is now read as part of the field; one typed into the cover by hand still starts a section of its own.
The docs say that each backup snapshot is a full copy of the store (issue 0587), beside backup.keep on the backups page (docs/concepts/the-store.md) and in the dispatch table's note on that key. The disk a project's backups take grows with the store's size times the snapshots kept, so a project with a large store may want a smaller keep.
The mechanical trope pass sees curly quotes and apostrophes (issue 0589). FMT-03, the rule for typeset characters in plain-text docs, held straight quotes where curly ones were meant, so it flagged every ASCII quote and apostrophe and missed every curly one. The phrase rules that spell a contraction or a closing quote, such as Here's the thing, it's worth noting or a dialog tag after a quote, matched only the ASCII form, so the same phrase typeset went unflagged. Each class now holds the curly character as well, and IN-PR-STYLE-004 and critic-prose run the patterns with LC_ALL=C.UTF-8 grep -iE, because plain BSD and GNU grep under the C locale read a curly quote byte by byte.
A compact carries the whiteboard skill whole, so a restart no longer loads it again (issue 0591). A compact carries an invoked skill only up to 20,000 characters, and in-whiteboard was more than twice that, so every compact left a truncated copy that /in-session loaded again in full, in every node of every project that runs the whiteboard. It now keeps every rule and drops the history and reasoning behind them, which stay in git, and fits under the limit. A bats arm holds every skill /in-session loads under it.
After a compact, /in-session invokes only the skills the compact did not carry whole (issue 0592). It said to invoke every skill unconditionally because a compact leaves them inactive, while the compact carries each skill invoked before it, so every restart loaded the carried skills a second time and each node read two contrary orders. A skill the compact carried in full is now left active, one it truncated or did not carry is invoked, and every skill is invoked when nothing says what the compact carried. The gate release and the whiteboard pickup still run, the pickup as intent wb pickup when the compact carried /in-whiteboard whole. intent/docs/working-with-llms.md says the same.
in-session, in-essentials and in-standards state their rules without their history (issue 0593). Paragraphs telling how a rule came about loaded at every session start and after every compact. They are cut and every rule they carried is kept; the history stays in git, and the gate release's in the comments of release-gate.sh.
A scoped intent sync --to-store <ID> no longer doubles the search index, and a store it doubled repairs itself (issue 0605). Every scoped ingest, the verb and the daemon's sync of one thread from disk, read the stored prose sections back and wrote them again, and the write re-inserted the sections of repository files and of whiteboard history beside the copies it had kept, so each run doubled both: a store could reach gigabytes in a day, with every write taking minutes. The write now keeps only the sections it owns, the store's schema moves to version 31, whose migration keeps one row per section and rebuilds the full-text index on the first open, and intent doctor shows, without counting it, a store that still holds copies. Every v3.1 and v3.2 release before this one carries the defect.
A first conversion from v2 no longer prints "the views of undeclared threads were not examined" before its ok: (issue 0596). The upgrade checked the views of the threads it leaves undeclared through the project as read before the conversion, which still declared the v2 version, so the check was refused as unmigrated and skipped on every first conversion. It now reads the project again once the version is stamped, and docs/migrating-from-v2.md no longer tells the reader to read past the line.
A v2 On Hold thread converts to an estate intent doctor passes (issue 0597). v2 keeps an On Hold thread, and any closed thread it never moved into a status folder, directly under intent/st/, and the prune of the v2 tree looked only in the status folders, so the thread's v2 info.md stayed at the path of its v3 view: intent doctor reported view skew on the fresh estate and the next intent upgrade refused to remove the file. The prune now removes a thread's v2 info.md files wherever they sit once the store holds the thread, and keeps every other file beside them as before.
intent --version no longer moves a legacy ~/.intent/ into the XDG layout (issue 0599). The move of a 3.0.1 home into ~/.local/share/intent and ~/.config/intent ran first thing in every intent process, before its arguments were read, so a build step that read the binary's version moved the operator's home and removed it. It now runs after the arguments are read and before the verb, and only for a verb that does work: --version, --help, info, version, help, every family's help, claude hook and intent bootstrap --check leave ~/.intent/ as they found it, and the check names it as the home the next verb that does work will move. Any other verb, bootstrap among them, moves it first and says so.
Skills install where Claude Code loads them when CLAUDE_CONFIG_DIR is set (issue 0604). Claude Code keeps its configuration, skills/ included, in CLAUDE_CONFIG_DIR when that is set, and Intent wrote skills under ~/.claude regardless, so on such a machine intent claude skills install put them where Claude Code never looked and the prompt gate looked for its releaser in the same wrong place. intent claude skills and subagents, intent doctor, the prompt gate, the session-start line and /in-session's release line now read CLAUDE_CONFIG_DIR when it is set and non-empty, and ~/.claude otherwise.
intent claude skills uninstall removes the skill's directory along with its files (issue 0602). It removed the files it had written and left the emptied directory in ~/.claude/skills/, and a second uninstall of the same skill then reported a change that did not happen. The directory now goes when nothing else is in it, and a second uninstall reports the skill as not installed; a file in it that Intent did not write stays, keeps the directory, and is named in the report.
Claude Code now loads a project's AGENTS.md (ST0083). Claude Code reads AGENTS.md only where no CLAUDE.md exists, so in every project Intent set up, which has both, a Claude Code session never read the contract AGENTS.md carries. A generated CLAUDE.md now opens with @AGENTS.md, which imports it, in either layout. intent claude upgrade --apply carries the line into a project's CLAUDE.md.
The templated .claude/settings.json denies editing the generated AGENTS.md (ST0083). AGENTS.md is regenerated whole, so an edit an agent makes to it is lost at the next sync. The template now carries permissions.deny rules Edit(/AGENTS.md) and Edit(/.claude/AGENTS.md), covering both layouts, and nothing against CLAUDE.md, whose user block is the place for a project's own directives. intent claude upgrade --apply writes it into a project whose settings are Intent's.
intent claude upgrade --apply keeps what a project added to its .claude/settings.json (issue 0606). A settings file carrying Intent's hooks was overwritten whole with the template, so permissions, a model pin or hooks the project had added beside Intent's were lost at every upgrade. Intent's hook entries and deny rules are now brought to the template's and every other key is kept; a file that matches the template is left byte for byte, and one that does not parse as JSON is held and named rather than overwritten. --force still writes the template whole.
A generated CLAUDE.md points at AGENTS.md for the four principles instead of carrying a second copy of them (issue 0598). CLAUDE.md repeated AGENTS.md's index of Highlander, PFIC, Thin Coordinator and No Silent Errors because Claude Code never read AGENTS.md; every generated CLAUDE.md now opens with @AGENTS.md (ST0083), which loads it, so a session received the index twice. Its "Rules of the road" section now names the four and points at AGENTS.md, and intent claude upgrade --apply carries the change into a project's CLAUDE.md.