Skip to content

Releases: conreo/paperclip-codegraph

v0.12.7 — the Exceptions panel now reports decisions, and finds the ungoverned path

Choose a tag to compare

@conreo conreo released this 23 Sep 05:13

paperclip-codegraph v0.12.7

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.12.7

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

The Exceptions panel told operators the wrong thing about their own decisions — and
missed the one state that matters.

What it said

On an organization where 20 agents had deliberately been left without an MCP client:

20 of 34 agents cannot receive these tools yet.
… Fix it per agent in its adapter settings, then restart that agent.

Every number was correct. The conclusion was not. Those 20 agents were a decision,
not a backlog — so the panel sent an operator looking for a fix nobody wanted, and it had
no way to say "this is already right".

The state it never looked for

Denying an agent here removes this plugin's tools. It does not remove the agent's
ability to start the organization's CodeGraph server itself, and that is a second,
separate path:

Path What it is Governed by Audited by
Plugin tools paperclip-codegraph:codegraph_search, via Paperclip's tool gateway the profile, per agent yes, every call
MCP server codegraph serve --mcp, spawned by the agent's own MCP client nothing no

A pi agent with --mcp-config therefore reads the codebase through a path this plugin
never sees — and if it is also switched off here, the switch appears to deny something
it does not deny. The panel never asked that question, so on this instance the state was
invisible: an agent could be revoked and fully reachable at the same time.

What it says now

  • The delivery warning is about MCP only, and says so: "N of M agents do not see
    CodeGraph under MCP."
    It then states what that agent can still do — "a missing
    convenience, not a missing capability"
    — because the plugin's own tools work with no
    MCP client at all. That was already true and the old copy implied the opposite by
    calling the state a failure.
  • A switched-off agent is no longer counted as a gap. Switching one off is the
    resolution, not the problem.
  • New: a switched-off agent that is still wired. Its own banner names the hole —
    those calls "never reach this plugin, so nothing here governs or records them" — and
    says what to do: remove the MCP client from the adapter as well. A client with no
    config is not flagged, because it names no server and every ambient discovery path is
    absent on a real host; that assumption is written down where it can be re-checked.
  • Per-row state is honest. A revoked agent on the MCP path reads "Revoked — but its
    adapter still reaches CodeGraph directly"
    rather than just "Revoked".

The counts moved into src/ui/exceptions.ts and are covered by tests/exceptions.spec.ts
(9 tests), because a rule that only exists as an inline filter can be changed without its
tests — which is how the false alarm survived this long.

How the claim was checked

The old copy claimed these agents "can still reach CodeGraph through the plugin API —
governed and audited". Rather than rewrite it on intuition, it was checked against the
running instance:

  • Paperclip documents POST /api/plugins/tools/execute as "the primary endpoint used by
    the agent service to invoke plugin tools during an agent run"
    , and it accepts agent
    identity.
  • The activity log holds 27 codegraph_tool_call rows attributed to an agent, plus
    tool_gateway.call_allowed / call_completed / call_denied records for
    paperclip-codegraph:codegraph_status|explore|node|search|files|callees|callers|impact.

So the sentence was true, the plugin path is real and does carry denials, and it is now
the part of the panel that stays.

Also in this release

The README gains "The third path, which nothing governs" — the first place this
plugin's documentation admits that a --mcp-config written into an agent's adapter
bypasses both Paperclip's gateway and this plugin. Anyone wiring agents up should know
that before they rely on a denial.

v0.12.6 — an existing index wins over descending into the checkout

Choose a tag to compare

@conreo conreo released this 18 Sep 10:31

paperclip-codegraph v0.12.6

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.12.6

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

v0.12.5 made the agent path descend into a project's checkout. It descended too
eagerly, and this corrects that.

What was wrong

The rule v0.12.5 added was "the index lives at the checkout, so a folder that holds one
is the wrong path". Checking it against the host that reported the original problem
showed the premise is only half true. CodeGraph searches upward for .codegraph:

$ cd …/0925bda0-…/_default/dealthai && codegraph status --json
{ "projectPath": "…/_default",              ← resolved upward
  "indexPath":   "…/_default/.codegraph",   ← the container's index
  "fileCount": 129, … }

So dealthai — the shape v0.12.5 was written for — was already answered for. Its
index is at the container folder, and the old behaviour of handing CodeGraph
_default worked. Applying the descent unconditionally:

  • hid a working index. A call would be resolved to _default/dealthai, where
    there is no .codegraph of its own.
  • and broke it further. ensureIndex checks the path it is handed, would not find
    one, and with autoIndex on would run codegraph init …/_default/dealthai — a
    second index of the same code, 5 MB of it, and a different index answering
    afterwards. With autoIndex off — the default — the agent simply got "Project
    …/dealthai has no .codegraph index"
    on a repository that is indexed.
  • and misreported it. The settings page already showed the row as Not indexed,
    because the check was made at the checkout. Pressing Index now would have built
    that second index by hand.

(The multi-repository half of v0.12.5 was right and is unchanged: nothing indexes the
container of a project holding six checkouts, so descending is the only way to reach
one.)

What it does now

An index that already exists wins. resolveCheckout takes an injected hasIndex: when
the configured folder already answers, the path is kept exactly as it was, and the
descent only applies to a folder that does not answer. The rule is now:

Read and build where the index already is. Otherwise, find the checkout.

The same rule governs all three places the question comes up:

Surface Before Now
an agent's tool call descends, misses the container index, may build a second keeps the folder when it answers
a row's Indexed state checked at the checkout only checkout or the folder holding it
Index now / Rebuild targeted the checkout, building a second index targets wherever the index already is

readiness and index-status are deliberately left alone: they probe a path an
operator explicitly bound, and "is there an index at the path you bound" is a
defensible meaning for a diagnostic. Changing it there would make the surface used to
debug this harder to reason about, not easier.

Verified against every project on the reporting instance

The decision code was run against all six companies and every project folder, with the
real filesystem and the real indexes:

DEL 8f393fa5 _default: wsIndexed=true  effective=_default  rows=[(root):shown=true]
DEA 0925bda0 _default: wsIndexed=true  effective=_default  rows=[dealthai:own=false,shown=true]
VRO e77f5825 _default: wsIndexed=false effective=REFUSED [vroomy-backend, …, vroomy-superproject]
REG 2ccfb99b _default: wsIndexed=false effective=REFUSED [regency-app, regency-os]
SAK 5ebdaf48 pos:      wsIndexed=true  effective=pos       rows=[(root):shown=true]
SAK 3b2a1745 pos:      wsIndexed=false effective=pos       rows=[(root):shown=false]
GLU b1616c4b _default: wsIndexed=false effective=_default  rows=[(root):shown=false]
DEL 1fa33d8c _default: wsIndexed=false effective=_default  rows=[]          (no code)

Every project that was working keeps the exact path it had. dealthai shows its row as
indexed and resolves to the index that exists. The two multi-repository projects are
refused by name, which is the intended behaviour for a project nobody has bound a
repository for.

Verification

resolveCheckout covers the pair directly: the same directory with hasIndex true
keeps the folder, with hasIndex false descends — the two tests differ in nothing else.
tests/project-discovery.spec.ts asserts the row for a checkout whose container holds
the index reads indexed: true and that a row with no index anywhere still reads
false. tests/repository-selection.spec.ts asserts a container that answers is
not refused even while holding several checkouts.

npm run verify — typecheck, build, 527 tests, all passing.

v0.12.5 — an ambiguous project is refused, not guessed

Choose a tag to compare

@conreo conreo released this 18 Sep 10:22

paperclip-codegraph v0.12.5

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.12.5

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

Corrected in v0.12.6. This release says CodeGraph's
index "lives at the checkout, so handing it the folder one level above answers nothing
at all". That is wrong for the case that mattered: CodeGraph searches upward, so a
project indexed at its container folder is answered for from its checkout, and the
agent path was not broken for dealthai at all. The descent introduced here did fix
multi-repository projects — nothing indexes the container of one — but applied
unconditionally it hid the container index and would have built a second one inside
the checkout. v0.12.6 makes the descent conditional on the folder not already
answering. The rest of this note stands.

The agent side of the same defect v0.12.4 fixed on the settings page.

The gap

v0.12.4 made the settings page find the checkouts inside a project's container folder.
It left the agent path alone, and that path had the identical bug:

projectPath = resolveProjectPath(bindingPathFor(binding.path, root), { … });
// → the workspace: <project>/_default

A binding — or the workspace Paperclip hands a run — names the project folder. For a
multi-repository project that folder holds every checkout and is not a checkout itself,
so CodeGraph was handed a path with no index in it. The repository is indexed on the
host; the agent gets not indexed; and there is nothing in the answer to say why.

So a plugin that lists six repositories and cannot read any of them is half a fix. This
is the other half.

What a call does now

One function, resolveCheckout, applied to the path a call resolves to:

The project folder holds What the call reads
the checkout itself it, unchanged — the ordinary case, byte-identical to before
exactly one checkout that checkout — unambiguous, and plainly what was meant
several checkouts nothing. Refused, with the repository names returned
no checkout the folder, unchanged — it may be a package inside a monorepo whose index sits at an ancestor

The last row matters as much as the others: a git rev-parse that finds an ancestor is
CodeGraph's own business to resolve, and rewriting the path there would move a working
monorepo deployment somewhere nobody bound.

Why several is refused rather than guessed

The alternative was to read the first checkout, deterministically. It is deterministic
and it is wrong: nothing in a multi-repository project says which repository the
question was about, so the agent would answer out of, say, acme-api when the question
was about acme-web — a confident, well-sourced answer about the wrong codebase, which
is the worst failure mode code intelligence has. Quietly indexing one of six is worse
than refusing all six, because the refusal is visible.

The refusal had to be actionable, so it names what it found and what to do:

CodeGraph project "vroomy" holds 6 repositories (vroomy-backend, vroomy-docs,
vroomy-frontend, vroomy-infra, vroomy-proto, vroomy-superproject), so no repository
is selected. Ask a Paperclip admin to bind one of them in the CodeGraph governance
profile for your company.

The names are relativePaths — directory names relative to the workspace, the same
labels the settings page shows — so nothing about host layout is disclosed. The call is
recorded as ambiguous_repository with the candidate count, so "the agent said
CodeGraph refused" is answerable after the fact rather than a support round-trip.

Also in this release

  • verify-scope performs the same resolution, so it reports what a call would actually
    do instead of a path the call would have replaced.
  • The Repositories section says 0 of 6 repositories indexed for a multi-repository
    project rather than Not indexed, which hid how many there were to do.
  • Two stale comments: graph-projects was described as what "the graph view can draw"
    (there has been no graph view since 0.11.0 — it is what the settings page and the nav
    column read), and repositories explained indexing under a note about alias.

Verification

tests/repository-selection.spec.ts runs the real registered tool handler against a
real container folder: it asserts the refusal names all three repositories in order and
says what to do, that the audit row carries the candidate count, that a single nested
checkout is not refused, and that a binding outside allowedProjectRoots is still
refused by containment before the repository check runs at all.

tests/git-identity.spec.ts covers resolveCheckout directly, including the two cases
that must not change: a path that is already a checkout is returned unchanged, and a
path with no checkout is left alone.

npm run verify — typecheck, build, 521 tests, all passing.

v0.12.4 — a project's repositories are found wherever they are

Choose a tag to compare

@conreo conreo released this 18 Sep 10:10

paperclip-codegraph v0.12.4

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.12.4

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

A project's repository is now found wherever it actually is, not only at the folder
root.

The report

On the VRO organization the dashboard said no repository, on a host that held six
of them. The question was the right one — why is my repo not detected? — and the
answer was that the plugin was asking the wrong question about the workspace.

What was wrong

graph-projects and repositories resolved a project's workspace and then required
the workspace itself to be a checkout:

// before
if (!workspace?.repoUrl && !(await isGitRepository(indexAt))) {
  skipped += 1;
  continue;
}

That is true of the simplest deployment — one project, one clone, .git at the top —
and false of the shape Paperclip actually creates for a multi-repository project. A
managed folder is a container:

<company>/<project>/_default/          ← the workspace, not a repository
├── vroomy-backend/    .git
├── vroomy-frontend/   .git
├── vroomy-docs/       .git
├── vroomy-infra/      .git
├── vroomy-proto/      .git
└── vroomy-superproject/ .git

VRO's project has no repo_url and no .git at _default, so both halves of the
guard were true and the project was silently skipped. Not "not indexed" —
invisible. dealthai was broken the same way one level down (a single checkout in
_default/dealthai), which is why that organization's plugin showed nothing to
configure while its code was indexed on the host.

What it does now

findRepositories walks the workspace and its immediate children — two depths,
deliberately, because a deep search eventually finds a vendored checkout inside
node_modules and indexing a repository nobody meant to index is worse than not
finding one. Every checkout it finds becomes its own row:

  • its own identity. A repositoryKey — the path relative to the workspace, ""
    for the workspace itself. A directory name, never an absolute path, so it is safe to
    render, safe to log, and safe to send back. index-now takes it, so Index now on
    the third of six checkouts indexes that one.
  • its own name. A project with one checkout keeps the project's name, because that
    is the label the operator gave it. A project with six cannot — six rows all called
    "Vroomy" is not a list — so each names itself from origin and the project becomes
    the aside.
  • its own index state, and its own Index now / Rebuild.

The Repositories section now groups by project, because the on/off switch is a
per-project control: six identical switches that all move together is not a decision,
it is a puzzle. The switch belongs to the project, and its checkouts are listed under
it. The Index section stays one row per checkout, because indexing is per repository.

Two cases that keep working

The guard existed for a reason, and both reasons are preserved rather than dropped:

  • A project pointing into a larger checkout — a package inside a monorepo. The
    workspace holds no .git and no child repository, so discovery alone would answer
    "no repository" for a project that is plainly in one. Paperclip's own repo_url
    keeps that project listed as a single candidate, and git rev-parse still resolves
    the ancestor where the index lives.
  • A checkout that is not on disk yet. Same fallback, and a row saying "not indexed"
    is more useful than the project vanishing.

A folder with no code at all — a backlog idea, a cancelled onboarding project — is
still not a repository and is still counted rather than listed, so "nothing here"
stays distinguishable from "three projects, none with code".

Also in this release

  • The README's troubleshooting section described a data key 0.11.0 deleted.
    It documented graph-diagnose and a JSON payload it can no longer return — no
    handler is registered for that key, so an operator following the documented curl
    got No data handler registered for key "graph-diagnose". The section now reads
    graph-projects, which is what the page itself reads, and shows how to tell the
    three causes apart from its output.
  • repositoryKey is recorded in the index audit row, so an index built for the wrong
    checkout of a multi-repository project is visible after the fact.

Verification

tests/project-discovery.spec.ts runs the registered graph-projects handler over
real temporary workspaces in both shapes, built with real git init and a real
origin. It asserts the six-repository project yields six rows, the nested
single-checkout project yields one, the ordinary project is unchanged, a project with
no code still yields none, and no absolute path appears anywhere in the response.
Each of those tests also asserts the old predicate would have skipped the project,
so the regression is stated rather than described.

tests/repository-rows.spec.ts covers the naming rule (including an empty
repositoryKey being a key and not a missing value, which is what would silently
index the wrong checkout), and tests/git-identity.spec.ts covers discovery itself,
including the repo_url fallback and the fact that it does not fire when a checkout
was already found.

npm run verify — typecheck, build, 511 tests, all passing.

v0.12.3 — the warning names the right cause

Choose a tag to compare

@conreo conreo released this 16 Sep 21:07

paperclip-codegraph v0.12.3

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.12.3

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

The "cannot receive these tools" warning was naming the wrong cause.

What it said, and why it was misleading

On an organization where the plugin had never been configured or activated at all,
the Exceptions section said:

5 of 11 agents cannot receive these tools yet. An active profile only makes the tools
allowed. An agent also needs an MCP client pointed at this organization's MCP config…
Fix it per agent in its adapter settings, then restart that agent.

Every sentence is true of a different situation. When the plugin is off, no agent
receives anything whatever its adapter says — so the adapter is not the problem, and
that paragraph sends an operator to the wrong settings page to fix it.

Off is exactly the state a fresh organization is in: GlucoChef, dealthai and
Regency have no config row and no profile at all, so the plugin is off by default
there. The warning was their first impression of the feature, and it was wrong.

Two states, named separately

  • Plugin off — "CodeGraph is off for this organization, so no agent receives these
    tools yet whatever its adapter is set to. Switch it on at the top of this page, and
    this section will say whether anything else is still missing."
    No mention of adapters.
  • Plugin on, wiring missing — the wiring warning, now opening with the fact that
    earns it: "CodeGraph is on, and an active profile makes these tools allowed — but an
    agent also needs an MCP client…"

The off-state note comes first in the conditional chain, so it wins when both are true.

Testing

486 tests, 481 passing and 5 skipped. Two new ones: that the off-state explanation
precedes the wiring warning in the chain, and that revoked agents stay excluded from
the count — an agent somebody switched off is a choice, not a gap.

v0.12.2 — switch matches the host exactly

Choose a tag to compare

@conreo conreo released this 16 Sep 20:58

paperclip-codegraph v0.12.2

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.12.2

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

The switch now matches Paperclip's own, to the pixel.

What was wrong

Two details, both invisible in a diff and obvious on screen beside the host's rows.

The thumb was a square — 16×16. The host's is h-4 w-6: 24 wide by 16 tall,
an oval. A square thumb in a capsule track reads as slightly off without it being
clear why.

The track's 2px border was doing double duty. The host's track is h-5 (20px)
including a border-2, so its inner box is 16px — exactly the thumb's height, which
is what makes the thumb sit flush. Mine got there by accident rather than by the same
arithmetic.

The off state also ran bg-input at full strength where the host uses bg-input/90 —
90% opacity, a slightly softer grey.

Matched to the markup

Transcribed from a real settings page rather than from the component source alone:

track: relative inline-flex shrink-0 items-center rounded-full border-2
       transition-all h-5 w-11 border-transparent bg-input/90
thumb: pointer-events-none inline-block rounded-full bg-background shadow-sm
       transition-transform h-4 w-6 translate-x-0
  • data-slot="toggle", so anything the host targets by that attribute finds this one;
  • role="switch" with aria-checked, unchanged — it was already a switch, not a
    checkbox.

The travel is derived, not written down

The thumb's travel is 44 − 2×2 − 24 = 16. That arithmetic is now in the code as
arithmetic:

const THUMB_TRAVEL = TRACK_WIDTH - TRACK_BORDER * 2 - THUMB_WIDTH;

A literal 16 would silently desync the moment any of those three changed — which is
exactly the class of mistake this release is fixing.

Testing

484 tests, 479 passing and 5 skipped. Four new ones pin the geometry as numbers, since
that is what it is: the track and thumb sizes, the 2px border, that the travel is
derived rather than hardcoded, and that the host's arithmetic still comes out at 16.

v0.12.1 — credential masking and delthai wiring

Choose a tag to compare

@conreo conreo released this 16 Sep 20:54

paperclip-codegraph v0.12.1

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.12.1

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

Two things: a credential leak this plugin was capable of, and the MCP wiring extended
to a second organization.

A clone URL can carry a token, and this plugin was reading it

git remote get-url origin returns whatever is configured, and a CI-provisioned
checkout often carries a token in it:

https://oauth2:glpat-…@git.example.com/group/repo.git

This plugin reads that URL to label a repository — the identity work in 0.9.2 — and a
label gets rendered, logged and written into audit rows. The URL itself was returned
to callers unmasked. Found while wiring the second organization, not by a report.

redactRemoteUrl now strips a user:secret@ authority at the boundary, before
the name is derived from it, so neither the URL nor the label can carry a token.

It redacts only when a secret is present: ssh://git@github.com/… has a user but no
password, and masking git there would destroy information rather than protect any.
The first version of the fix over-redacted exactly that case, and the test caught it.

Six tests, including the real GitLab form and the assertion that the token is absent
from the result for three URL shapes.

If your instance uses a tokenised clone URL, rotate the token. It has been sitting
in a config file and in the output of every git remote -v an agent runs, which is a
larger exposure than this plugin.

MCP wiring extended to delthai

The wiring added for sake — a --mcp-config path in each agent's adapter arguments,
and a CodeGraph stdio server in the company's own MCP file — now covers the second
organization that can actually use it.

Org pi_local agents wired why
DEL 33 33 Has an indexed repository (640 files, 12,085 nodes, 32,373 edges) and the plugin enabled
SAK 17 6 As before — the five engineers and the CEO
DEA 10 0 Its workspace is not a git repository and has no index
GLU 11 0 Two git workspaces, neither indexed
REG 6 0 No repository workspace at all

An MCP server pointing at a repository with no index answers nothing, so wiring those
would have been a server that fails on first use. Extending to them is a two-step
job — build the index, then wire — and the settings page has the button.

opencode_local agents are excluded on purpose: the wiring passes pi-mcp-adapter,
which that adapter does not use. sake and delthai each have one such agent.

Testing

480 tests, 475 passing and 5 skipped.

v0.12.0 — settings rebuilt as a Paperclip settings page

Choose a tag to compare

@conreo conreo released this 16 Sep 20:45

paperclip-codegraph v0.12.0

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.12.0

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

The settings page is rebuilt as a Paperclip settings page, not a plugin form.

What changed, and why it is a rework rather than a restyle

It was five bordered cards — Configuration, Activate, Repositories, Indexing,
Exceptions — with checkboxes, a Save button for everything, and explanatory prose
written for a reader who already knew the answers. Next to Paperclip's own General
settings it read as a form bolted on.

The reference was read, not guessed: ui/src/pages/InstanceGeneralSettings.tsx and
ui/src/components/ui/toggle-switch.tsx. What those files do, and what this now
does:

Page A max-w-4xl column with sections separated by space, not a card around each.
Section One idea: a text-sm font-semibold heading, a short muted sentence, then its controls.
Setting Heading left, control right — flex items-start justify-between gap-4.
Switch A capsule that writes immediately. No Save button, because General settings has none, and a form that needs saving is one that can be abandoned half-changed.
Typed values The one place a Save button appears, and it only appears once the text actually changed.
On state The host's status green, not primary — which its ToggleSwitch records as a deliberate ruling.
Failures One destructive-tinted banner, rather than a message beside each control.

The copy was rewritten to say what happens

The old text was accurate and unreadable — "Availability follows the Paperclip
project an agent is working in, so this is set per repository rather than per
agent"
. Now:

  • Repositories — "An agent reaches the one its Paperclip project uses, so this
    is set here rather than per agent — and switching one off can only narrow."
  • Index — "a repository with no index answers nothing. Building one reads the
    whole repository, which is why it happens when you ask rather than by itself."
  • Directories CodeGraph may read — "A limit, not a list." The field nobody
    could read is now answered in its first four words.
  • Exceptions — "Every agent reaches the repositories its projects use, so there
    is nothing to grant here. This is only for taking that away from one agent."

Two things stay because they were asked for and are genuinely useful: the org name
in the page title, and the MCP delivery gap callout — which now names the fix
("Fix it per agent in its adapter settings, then restart that agent") as well as
the problem.

Checkboxes became switches, and rows became rows

Repositories and agents were checkbox lists; they are now rows with the item on the
left — name, then a muted status line — and a switch on the right. A repository row
reads POS · pos / Indexed · 587 files, 5250 symbols and a switch, rather than a
tick box and a sentence about what ticking means.

Testing

475 tests, 470 passing and 5 skipped. New: 12 that pin the structural rules as
source-level assertions, because the things that matter here are layout decisions
types cannot see — the reading width, the split row, the switch writing immediately
rather than behind a Save button, and the status green over primary.

They also pin the copy: that the switch is never described as a grant, that an
unindexed repository is explained rather than only reported, and that the directory
field says "a limit, not a list".

v0.11.0 — reader removed

Choose a tag to compare

@conreo conreo released this 16 Sep 20:38

paperclip-codegraph v0.11.0

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.11.0

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

The hand-built graph page is removed. The plugin now does the part it is
actually for, and nothing else.

Why it came out

For several releases this plugin shipped its own reader: a three-pane Symbol view,
an architecture Map, entry points, and a dead-code list. Every one of those already
exists in CodeGraph's own UI, and is better. That UI is under active
development — its own unreleased notes add a Screens tab, rework the Steps layout
several times over, and change the very map and screen layouts this plugin had
reimplemented.

So the reader could only ever fall behind, and the hours spent on it were hours not
spent on the part that is genuinely pluggable. It is gone.

What was investigated first, and why reuse was not adopted

The adapter seam in CodeGraph's UI is real, and it was tested rather than assumed:

  • ui/src/lib/api.ts is explicit — "a host that already holds the index — the Pro
    app — installs its own"
    adapter. GraphAdapter is 14 methods, with steps
    optional and trails explicitly specified to answer {trails: [], readOnly: true}
    so a host shows the section as empty rather than a dead Save button.
  • Their UI builds standalone from ui/src with Vite and svelte — 1.40s.
  • A proof of concept ran their real Map view against this plugin's data: 40
    module boxes, their legend, their "foundations — depend on nothing below"
    caption, no page errors.

It was still not adopted, for a reason that only showed up when checked:

  • their ui package is private: true and not published to npm;
  • the built viewer ships inside a 123 MB vendored Node runtime, not as assets
    that can be served;
  • installing from git gives only files: ['dist','scripts','README.md'] — no
    ui/ source
    .

So consuming it means a build step that fetches and builds their source on every
update, plus implementing 16 API endpoints against wire.ts (1,033 lines, 78 types).
That is a real maintenance commitment, and the proof of concept found a bug of
exactly the kind it would keep producing: the module dependence counts came out
398 where theirs said 36, because counting all cross-module edges is not the
same as counting files that reference in. The picture looked right; every number
was wrong. A screenshot would not have caught it.

What the plugin is now

Surface Where
CodeGraph the nav column — index state at a glance
CodeGraph Settings → Plugins — all configuration

And behind them, what Paperclip actually needs from a plugin:

  • the eight CodeGraph tools, governed and audited through Paperclip's tool
    gateway, with per-project and per-agent narrowing;
  • the MCP wiring that makes those tools reachable by an agent at all;
  • repository resolution — a repository is a Paperclip project's workspace,
    never a path an agent types.

To read the graph, run codegraph ui on the host. It is a local, read-only viewer
for the project you already indexed and needs no Paperclip wiring.

Removed

  • src/ui/page.tsx, map-view.tsx, views-panels.tsx, views.ts,
    route-sidebar.tsx, reader-layout.ts, search-intent.ts, and their tests.
  • The page and routeSidebar manifest slots, and the ui.page.register
    capability — which also means the host's Back button no longer applies, because
    there is no page to go back from.
  • Eight data handlers that only the reader used: graph-reader, graph-map,
    graph-entry-points, graph-dead-code, graph-search, graph-neighbourhood,
    graph-source, graph-diagnose.
  • The nav entry is a status row rather than a link, since there is no longer a page
    to link to.

Kept: the settings page in full (configuration, Activate, repositories, indexing,
exceptions), the nav entry's index state, and every tool and governance path.

Bundles: UI 130 KB → 51 KB, worker 737 KB → 707 KB.

Testing

463 tests, 458 passing and 5 skipped. Removing views removed their tests too —
which is the honest accounting: this is a smaller plugin, not a better-tested one.

v0.10.1 — overlays, toolbar, honest questions

Choose a tag to compare

@conreo conreo released this 16 Sep 20:11

paperclip-codegraph v0.10.1

Install

npm install -g @colbymchenry/codegraph@1.6.0   # the CodeGraph CLI, if you do not have it
paperclipai plugin install paperclip-codegraph@0.10.1

Pin the version: Paperclip stores a caret range against what was installed, and for a
0.x version a caret does not cross a minor release, so a bare plugin install is a
no-op once the next minor is out.

The plugin installs disabled. Nothing changes for any agent until an organization
turns it on, in Settings → Plugins → CodeGraph.

Chrome placement, a search bar that matches the viewer's, and one promise the
placeholder was making that this plugin could not keep.

The Key is an overlay, bottom-left

It was a strip above the canvas, taking vertical space from the picture. It is now
an absolutely-positioned panel in the bottom-left of the graph, collapsible with
its Key ▾ toggle, exactly as CodeGraph's own viewer has it — that is what the
overlay is in the original, verified by reading its geometry rather than guessing.

Zoom and reset are an overlay, bottom-right

Same story: the controls moved from a toolbar to a compact vertical stack in the
bottom-right of the graph, in their own bordered card. Both overlays use
pointerEvents: none on the wrapper and auto on the contents, so drag-to-pan still
works through the gaps between them.

The toolbar reads like the viewer's

  • Search is first and widest (flex: 1 1 520px, capped at 720px — the viewer's
    own input measures 708px). It was previously squeezed behind a "CodeGraph" label
    and a repository name, which is why it looked cramped.
  • The "CodeGraph" label is gone. The page it sits on is already called
    CodeGraph; the rail says so too. It was spending the width the search needed.
  • Repository and index state moved right, where they change once a session
    rather than constantly.
  • The placeholder is now the viewer's own: Search a symbol or file, or ask "how
    does execute reach getFile" — press / to focus
    .

The placeholder was promising something this plugin does not do

That sentence offers a natural-language question, and treating it as a symbol name
returned "No symbol matches" — the search box failing at something it advertised.

A question is now recognised (src/ui/search-intent.ts, 8 tests, pure) and
answered with what is true: that answering it needs the path search behind
CodeGraph's own Flow view, which this plugin does not implement because it keeps no
call-path history — and then four things that do work, including opening either
symbol in the reader so the path can be followed by hand from either end.

Recognising the pattern also means the common case is protected: createOrder,
orderEngine.ts, GET /api/health and src/api are all still plain searches. The
parser only fires on a phrase with two distinct symbols and a path verb, and falls
back to a name search on anything malformed — a misread question would replace a
working symbol list with an explanation.

Testing

511 tests, 494 passing and 17 skipped without an index. New: 8 for the question
parser, including the placeholder's own example and the cases that must not be
read as questions.