Repository navigation
Graphicle 0.1.3
Every crate is at 0.1.3, and graphicle --version prints
graphicle 0.1.3 (core).
Code graph
- Markdown front matter that opens a bracketed list or mapping on a key's
line (key: [orkey: {) and continues it on lines indented no further
than the key, such as a closing]at the start of a line, is now read as
YAML. Graphify's YAML parser (PyYAML) ignores indentation inside brackets,
but Graphicle's rejected such lines, so the page's stored front matter fell
back to plain text: its fields became strings and the list's entries were
lost. Anapm.ymlmanifest written this way, which the same parser reads,
gave a manifest parse error and is now read too. This was the cause of the
known difference in the graph aftergraphicle graph updateon
gohugoio/hugo. - Linking imports across a workspace's projects is incremental. After a sync,
a project's imports are linked again only when the project changed, when a
project it can import from changed what it exports, or when the set of
linked projects changed. The other projects keep their links, and their
graphs are not loaded again: each project's export index is kept with the
links. The links recorded are the same as those of a full pass. The
graph_linkresult lists the projects linked again (relinked) and those
whose links were kept (reused).
MCP Registry
- Each MCP bundle holds the Graphicle icon, which Claude Desktop shows beside
the extension, and the registry entry links to the same icon
(packaging/mcpb/icon.png). The workflow builds a release's bundles with
the scripts on main, so the bundles of 0.1.2 have the icon too.
Agents
- Agents are told when Graphicle helps and when grep is enough, in the same
words wherever they read it: userecall_projectorquery_graphfor
where or how something works, for questions across files or history, and
before changing unfamiliar code; for an exact identifier you already know,
grep is enough. Answers cite file and lines.- Claude Code's and Codex's session-start hook prints this as one line at
the start of every session in a project (Claude Code still skips a
resumed conversation), before the reviewed memory, open work and stale
memory it printed already. A project with nothing reviewed, open or
stale used to get no session-start text. - The server's instructions start with it, in the essentials set and in
the whole server. - The descriptions of
recall_project,query_graph,get_node,
get_neighborsandshortest_pathend with one sentence on when to use
the tool instead of grep. Apart from these sentences, the whole server's
instructions and tools (--tools all, which the other agents get) are
0.1.0's. - The Graphicle section that setup writes in
AGENTS.mdandCLAUDE.md
says it. Running setup again brings an existing section up to date, and
graphicle disconnectremoves it as before.setup --tools allstill
writes 0.1.0's section. - The opt-in guard hook's reminder before a search says it too.
- Claude Code's and Codex's session-start hook prints this as one line at
graphicle setup --prompt-context(off by default) adds a Claude Code
UserPromptSubmit hook: before each prompt that is a code question (the
classifiercontextuses), it runsgraphicle contextand gives the
packet's Markdown, at most 8,400 characters, as the prompt's additional
context. Short prompts, questions in plain words, folders of no project,
failures and answers slower than 10 seconds add nothing; the prompt is
never refused, and the hook waits up to about 10 seconds. The prompt
reachesgraphicle contexton its standard input (graphicle context -
reads the question there).graphicle disconnectremoves the hook.
Context and recall
graphicle contextprints at most 8,400 characters by default (new
--max-chars; it was 4 characters per--max-tokenstoken, 12,000 by
default), so a prompt hook that prints the packet under a header stays
below the 10,000 characters Claude Code shows in full. With only
--max-tokens, the packet still holds 4 characters per token.- A
notes_firstoption, off by default:notes_first: trueincontext,
graphicle call context, the SDKs and answers,graphicle context --notes-first, or over MCP besiderecall_project's arguments (and
graphicle mcp --set notes_first=truefor a server). Every packet's
notes_firstsays what applied. It turns on three changes:- A question that names no code (no backtick span,
snake_caseor
camelCasename,Type::member,call()or code file) takes the first
50 files of the fused ranking, one passage each. Code files keep their
places; the notes and documents among them are ordered again among the
notes' places: a note whose name or folder matches the question's words
(Porter stems, so close variants match), whose headings match, or with a
newer date (the latest ISO date, up to today, in its path or text) comes
first. A question that names code keeps the code ranking. - A packet quotes one window per file, and one of files with identical
bytes; the next files take the freed places (notes_first.one_per_file
counts what was dropped).include_tests: true, which--tools all,
graphandmemorysend forrecall_project, and an explicit
origin_quotakeep the windows as ranked. - Excerpts say how old they are. Each excerpt of a project file cites the
date its file last changed ((changed 2026-10-15 05:10 UTC): the last
commit when Git tracks the file unchanged, else its modification time).
An excerpt that names code (a code-shaped document link) whose file
changed later saysmay be stale: <file> (defines <name>) changed <date>. Excerpts are not compared with one another, and dates do not
reorder them. Imported notes and documents carry no review state, so the
stale flags of reviewed memory never applied to them.source_age: true
orfalsesets the dates alone.
- A question that names no code (no backtick span,
- An identifier route for
context: a question that is an identifier, or
names identifiers and only asks where they are defined or used
(`parse_config`,where is Store::open defined,who calls ParseConfig), gets each name's definitions and references from the code
graph aspath:linelines within the call's budget, and one line with the
titles of the reviewed memories linked to them, instead of the full
retrieval's excerpts (the packet'sevidenceis empty).recall_project
in the essentials set andgraphicle contexttake it unless told
otherwise (identifier_route: false,graphicle context --no-identifier-route,graphicle mcp --set identifier_route=false); the
HTTP API,graphicle call context, the SDKs, the app and--tools all,
graphandmemorytake it only when a call setsidentifier_route: true. A name is a backtick span, asnake_caseword, a camelCase or
PascalCase word with a capital inside it, a dotted or::path, or a
callname(). A name alone takes the route; other words may only ask
where the names are or what uses them, and one of them must. A question
in plain words, one that asks for more (what a name is, its code or
members, what it calls, where it is mentioned), a call withneeds, and
a name the code graph does not define keep the retrieval. Every project
packet'sroutesays which path ran, and why the retrieval did. - Code questions rank source files first (
code_first,"auto"by
default). A question that names code (an identifier or a code file) or
reads like an issue or bug report (a code block, a stack trace or error
line, or two report words such as crash, error, fails, expected) counts
the passages of documentation, test and vendored or generated files at a
quarter of their fused score, in the ranking itself, so the excerpts and
the budget go to source files first; the code-graph arm leaves Markdown
nodes out for such a question. Tests are recognised by folder and name in
Rust, Python, Go, Java, Kotlin, C#, JavaScript, TypeScript, C, C++ and
Ruby. A question about documents, notes or decisions that is not a report
keeps 0.1.2's order, and test files keep their weight when a question
that is not a report names a test or the call setsinclude_tests: true.
A test or document that defines a code name the question names (with an
underscore or an inner capital, such as a test helper or a fixture) keeps
its weight when no source file defines that name.
A camelCase name needs two lowercase letters before its capital, digits
between allowed (getChoices,utf8Decoder; notiPhoneoreBay);
a PascalCase name counts when it has a capital inside it, as for the
identifier route (IsNull,ParseConfig).
code_first: falsekeeps 0.1.2's order for any question,trueranks
source first for any question. The packet'scode_firstsays what
applied and how many files of each kind it lowered. - A code question's query is its content, not its instructions
(query_focus,"auto"by default): when the question marks its content
(tags of its own such as<issue>or<pr_description>, opening at the
start of a line, or--- BEGIN ISSUE ---/--- END ISSUE ---lines),
the marked text with every word, followed by the names of code in the
prose outside (placeholders such asClassName.method_nameand fenced
examples left out); without marks, the question without general words of
instructions (find, fix, change, list, file, function, please, ...).
Either way a code host's links to files (.../blob/<ref>/src/x.rs#L10)
become the files' paths, and other web addresses and commit hashes are
left out. BM25, the code-graph arm, the choice of files past the passage
bound, a local reranker and the excerpts' focus read it; the packet keeps
the question, and itsquery_focussays what was marked and left out. A
prompt that wraps an issue in instructions used to rank by the
instructions' words as much as the issue's.query_focus: falsereads the
whole question. - The identifiers and file paths a code question names rank their files
(identifier_arm,"auto"by default). The identifier route kept the
retrieval for a question that asks more than where names are, and dropped
the names it had found; now a code question's identifiers (from code
blocks and spans: every identifier; from prose:snake_case, camelCase,
calls, qualified names) are matched as whole words, case-sensitively, in
the project's passages, and found at their definitions in the code graph.
Each file scores the weights of the names it holds (rarer names weigh
more, a definition counts twice) plus a bonus when the question names its
path, and its two best passages join the fusion as the armidentifiers
(arm_weightskeyidentifiers). The packet'sidentifier_armlists the
names and paths used; the route's report saysnames_fused.
identifier_arm: falseleaves the arm out. - After its excerpts, a code question's packet lists the paths of the next
10 ranked files that no excerpt quotes, one line each (more_files, 0 to
40; left out, 10 for a code question and 0 for any other). The room is
kept from the excerpts' share, at most an eighth of the budget, so the
packet stays withinmax_charsandmax_tokens; atgraphicle context's 8,400 characters the excerpts quote three or four files, and
the files after them used to be cut. The packet'smore_fileslists
them, andgraphicle contextprints them under "Next ranked files". code_first,query_focus,identifier_armandmore_filesare flags
ofgraphicle context(--code-first,--query-focus,
--identifier-arm: auto, true or false;--more-files N) and switches
ofrecall_projectover MCP thatgraphicle mcp --setcan fix; packets
echo them inmechanisms.switches.- A
contextquestion over 16,000 bytes is shortened instead of refused:
to its tagged content when that fits, else to its beginning, cut at a
line end, followed by the identifiers and file paths of the part cut
(within 3,000 bytes). The packet'squestion_shortenedgives the
question's size, what was kept and how many names were added. A long
issue pasted into a prompt hook used to get no packet. - Past the per-question bounds (50,000 documents or 40,000 passages), the
files a question reads are chosen by a BM25 score of its words in each
file (rarer words weigh more, a word's count is divided by the file's
length, a word in the path counts twice more), among at most 64 words,
those written as code first. The count of the first 24 words a file
holds chose them before, so large files filled the bound.
Memory, recall and answers
get_nodelists, for its symbol, the current reviewed memories anchored to
it and the documents the reader may read that name it (linkedin its
structured answer, and a line in its citations text). Stale, draft and
retired memories are never listed. A connection to one project lists that
project's only, also whenreporeads another project's code graph.- Recall and answers take a
symbol_linksswitch for the links between
reviewed memory and code symbols. Left out, a packet counts the links of
its excerpts and memories (symbol_links, statuscounted) and follows
none.symbol_links: truefollows them one step each way: an excerpt of
code brings in the current reviewed memories linked to a symbol inside it,
and a reviewed memory brings in the current code of the symbols it is
linked to.symbol_links: falsereads none.graphicle mcp --set symbol_links=true(orfalse) fixes it for a server. - The packet's
mechanismsnow fillsymbol_links_enabled, and
links_used.memorycounts the memory links an answer used. memory.templateexports a project's reviewed procedures and decisions as
an engagement template. Each memory keeps only its kind, title, body and
state: quotes, links, ids, dates and authors are left out, and the
project's names, the files and symbols it cites, e-mail addresses, links,
credentials and terms you list are replaced by placeholders.memory.import_packimports reviewed memories, from an export or a
template, into another project as drafts to review. Symbol links are
matched to that project's code by path, qualified name, kind and ordinal,
and follow a symbol that moved to another file. Quotes are kept only where
that project's own sources hold them. Whatever cannot be matched is
dropped and counted.
MCP
workspace_map, a tool of workspace connections (thegraph.map
operation over HTTP, the SDKs andgraphicle call), maps the projects an
access key can read, 8 at a time: for each project, its files, documents,
code symbols, memories and links (imports from and into the other
projects, document mentions linked to its code, code symbols its memories
are anchored to), and the recorded imports between the projects, by pair.
Each project is counted as the key's own reads of it count it, and a
project the key may not read is left off the map.recall_projecttakes across_reposwitch for the step of a workspace
recall that follows imports between projects:falseturns that step
alone off, andtrueturns it on even withgraph_retrieval: false. Left
out, it followsgraph_retrieval.- Every recall packet echoes the switches in force under
mechanisms.switches.graphicle mcp --set(andserve --mcp-set) also
fixescross_repoandscope(projectorworkspace), and refuses a
switch it does not know. graphicle mcp --manifestprints what the server would serve, as JSON,
and exits: the program's version, edition and sha256, the tools and
instructions with their sha256, the switches it fixes, and the schema and
format versions.
Sync
- A folder sync reads the files Git tracks even when a
.gitignore
pattern (or.git/info/exclude, or the global excludes) matches them
(git ls-files --cached --ignored --exclude-standard): Git versions them
with the rest, so they are the project's sources, as in a repository that
ignores its build outputjsonata.jsand trackssrc/jsonata.js. Files
Git does not track are left out by those patterns as before, and
node_modules,target, credentials and the other skipped names stay
out, and so does a file an.ignorefile leaves out. The freshness check
reads the same files, and the sync's output counts them
(tracked_ignored).graphicle config set sync.tracked_ignored false
leaves tracked files that a pattern matches out, as 0.1.2 did; the
environment variableGRAPHICLE_SYNC_TRACKED_IGNOREDoverrides the
setting. The refusals of a project or folder too large say that
.gitignoreand.git/info/excludecover untracked files only.
Data
graphicle offboard --project PROJECTremoves one project's data from the
data folder: its sources, memory, code graph and history in the store, its
graph cache, and its copies in the backups kept in the data folder's
backups/folder. Other projects stay, in those backups too. It shows the
plan first and changes nothing until it runs again with
--apply PLAN_HASH, which carries out exactly that plan. It writes a
hash-chained deletion receipt that lists what it removed, touches nothing
outside the data folder, and names what it does not cover, such as backups
written elsewhere. A path it refuses (a link, or a backup with another
name) is never changed and may still hold the project, so the offboarding
is then reported as not fully verified.- Offboarding never follows a link in
backups/, such as agf-cachelink. graphicle backupwithout a path writes the backup to the data folder's
backups/folder.- On Windows,
graphicle offboardleaves every backup inbackups/as it is
and lists it as refused: Windows does not tell Graphicle whether a backup
file has another name outside the data folder.
Usage report
-
The owner's usage report (
GET /v1/workspaces/WORKSPACE_ID/usage) and the
Usage view of the app now show what Graphicle served this month (served):- the tokens of every MCP tool result and MCP resource read;
- over HTTP and through
graphicle callandgraphicle context, of every
operation an MCP tool runs and of the other reads of a project's
sources, memory, evidence or graph (such asmemory.exportand
document.original); - of the session-start context that capture hooks give a coding agent.
Tokens are counted with cl100k_base on the text served, by credential,
agent session, channel, tool or operation, project and UTC day. A result
that names no project but serves several, such as a recall over every
project of a workspace, is counted on those projects: its tokens split by
the bytes served from each, and the call once, on the largest share.
Operations that return only settings, counts or listings, such as
list_projects, are not counted. These are the tokens Graphicle returned,
not your agents' bill: Graphicle does not see your agents' own model calls. -
These counts never leave your machine. Graphicle keeps counters only, in a
newam_served_usagetable of the local store: no question, result,
source id or client session id.- Counting adds no write to a call; counts are written in batches a few
seconds later and when the program ends. - Rows go with their project and are kept 25 months, and an agent
session's rows are folded into rows without a session after 90 days. One
access key keeps at most 200 agent sessions a UTC day; the calls of
further sessions that day are counted under one shared session,
other-sessions. deletion.statelists the table as history.- The table is created the first time the new version opens an existing
store.
- Counting adds no write to a call; counts are written in batches a few
-
Beside them, the report lists Graphicle's own recorded model tokens by
credential and by model (model_usage_by_credential,
model_usage_by_model).coststays null. -
The MCP endpoints over HTTP (
/mcp/WORKSPACE_IDand
/mcp/WORKSPACE_ID/PROJECT_ID) send anMcp-Session-Idheader with their
answer toinitialize.- The server signs the id, and the usage report uses it only to group a
client's calls into one agent session. An id the server did not sign is
counted under one shared session,mcp:unverified. - A client that does not send the id back is served as before.
- Each
graphicle mcpconnection over stdio is one agent session. A
capture hook labels its start context with a digest of the coding
agent's session id, never the id itself.
- The server signs the id, and the usage report uses it only to group a
Store
- A store can record the oldest Graphicle that may open it, as a store format
(a newstore_readerstable, created when the new version first opens an
existing store). From this version on, Graphicle checks it before it
changes anything in a store, and refuses a store that needs a newer
program, naming the version it needs. Versions before 0.1.3 do not check. - A store can name credentials that a program must refuse unless it
enforces their restrictions itself: a table or view
credential_requirements(credential_id,capability). Graphicle
refuses each credential it names with a capability thatbuild.infodoes
not list, instead of granting the credential its role's full access, also
in a restored portable backup. Graphicle Core lists none of these
capabilities. Graphicle 0.1.2 and older do not read the view and grant
such credentials their role's full access, so do not open a store that
names credentials there with them.
Extension interface
Extension::authorizelets an installed extension refuse or narrow a
request of a credential other than the owner capability wherever Graphicle
authorizes one (Access): a permission, a repository, a route that names
a workspace, an operation, an MCP tool. It may narrow an operation's
arguments and set the most tokens a read's result may hold: a larger read
result is refused with 413, and a write's result is never refused once it
is saved.Extension::role_permitslets it define roles beside
Graphicle's, andExtension::grant_rolemay refuse a new credential on a
role it defines. The caller of a request is resolved by authentication
alone, so these hooks see every credential, whatever its role grants; an
error other than a refusal while resolving it fails the request.Extension::served_allowedlets an installed extension refuse a metered
MCP tool call, MCP resource read or HTTP operation of a credential other
than the owner capability, onceauthorizeallowed it, for example for a
quota.Extension::metered_operationsmeters an extension's own reads of
project text.- A refusal with status 429 carries
Retry-Afteruntil the next UTC month. - Core installs no extension, so it refuses and caps nothing, and the
command line and capture hooks are never refused for a quota. - A commercial edition for teams is in private preview.
- A refusal with status 429 carries
Extension::sourcesadds connector kinds beside Graphicle's (theSource
trait): their connectors are added, scheduled, synced and enforced on read
as Graphicle's own.Extension::vault_keylets an extension hold the key that seals the
store's vault, for example a key held by an external key service; the
vault then never falls back to the device key file.Extension::cross_site_postnames a POST route that an extension
authenticates by itself, such as a sign-in callback that another site's
page posts to. Such a request skips the origin and browser-mutation
checks; the host check stays.JobKind::cpu_bound()marks an extension's job kind as CPU-bound, so a
worker leases it only with a CPU permit, as it does Core's projections.- Routes under
/v1/workspaces/WORKSPACE_ID/usage/are outside the monthly
request budget, like the usage report.
Other changes
- rustls-webpki 0.103.16, webpki-roots 1.0.10 and webpki-root-certs 1.0.10:
certificate paths through the distrusted emSign intermediates are refused
(RUSTSEC-2026-0382 and RUSTSEC-2026-0381).
Install
brew install graphicle-ai/tap/graphicle
# or
curl -fsSL https://github.com/Graphicle-AI/graphicle/releases/download/v0.1.3/install.sh | sh -s -- --version 0.1.3On Windows (x86-64, preview), in PowerShell:
$env:GRAPHICLE_VERSION = '0.1.3'; irm https://github.com/Graphicle-AI/graphicle/releases/download/v0.1.3/install.ps1 | iexEach archive's SHA-256 sum is in SHA256SUMS and beside it in a .sha256 file.