@controlvector/cv-code
v0.2.13
Published
Control Vector cv-code — Markov-curated coding agent forked from opencode. Includes context curation that eliminates manual /compact, Permission Intelligence overlay, and RLM session mode.
Maintainers
Readme
@controlvector/cv-code
A coding assistant where the conversation has a position in your codebase.
cv-code is Control Vector's fork of opencode. v0.2.0 ships the architectural inversion: the conversation has an anchor (its position in the codebase), the workspace has memory (persistent facts across sessions), and the model can record what it learns mid-conversation. The system prompt shows what's near the anchor; memory facts ride above the working set in an invariants block; the model navigates by moving the position rather than searching from a cold start every turn.
What v0.2.0 brings
Three things you didn't have in v0.1.x:
- The conversation has an anchor. Symbols you mention and tool results build a weighted set of "where we are." The system prompt's working-set block is now Personalized PageRank over the anchor + cv-hub's call/import graph, modulated by detected workflow phase. The anchor decays with a 5-day half-life and persists per-workspace.
- The workspace has memory. Persistent facts surface in an invariants
block at the top of every system prompt. Four sources: explicit user
facts (
cvc cvhub memory add), repo-declarative auto-extraction frompyproject.toml/.editorconfig/tsconfig.json/ language-version pins /.prettierrc, deterministic correction-pattern detection over the trajectory log, and model-recorded facts via a tool call. - The model can record what it learns. New
cvhub_remembertool lets the model write a stable workspace fact mid-conversation. You see and confirm every fact via a TUI permission prompt — same UX asls/editprompts you already know.
The cv_search / cv_subgraph / cv_neighbors tools didn't go away — their
descriptions were reframed (Choice 3.18). They're now anchor-aware navigation
("teleport," "expand," "trace") rather than cold-start search.
Install
npm install -g @controlvector/cv-code
cvc auth login cv-hub # paste your cv-hub PAT
cd ~/your/repo
cvc # opens the TUIFirst-run UX (Sprint 7, v0.0.5) auto-detects your git remote and prompts to
configure cvhub.owner / cvhub.repo. If your repo isn't indexed on cv-hub,
local-scan fallbacks (ripgrep + recency-weighted ranking) keep cv_* tools
useful.
Upgrading
If you've previously installed cv-code on this machine, run:
npm install -g @controlvector/cv-code@latestcv-code does not automatically upgrade between releases. Each machine you use
cvc on needs its own install. Check your version with cvc --version.
What you'll see
Open cvc in a Python repo. Status line populates over the first turn:
cvhub: configured | anchor: empty | mem: empty | graph: readyAfter a few turns talking about the auth flow, β2 has extracted facts from
pyproject.toml on session start, and the anchor has accumulated symbols
you mentioned:
cvhub: configured | anchor: 7(auth) | mem: 3β2 | graph: readyThe system prompt the model sees now includes an invariants block and an anchor-driven working-set block:
[CV-CODE INVARIANTS — 3 facts]
CURRENTLY RELEVANT
- Python version constraint: >=3.11 (per pyproject.toml [project])
- Indent: 4 spaces (per .editorconfig [*])
- Code style: line length 100 (per pyproject.toml [tool.black])
[CV-CODE WORKING SET — anchor: auth, phase: explore]
Top 6 symbols ranked by PPR over anchor:
1. AuthRouter — apps/backend/src/auth/router.py
signature: class AuthRouter(BaseRouter):
2. verify_token — apps/backend/src/auth/jwt.py
signature: def verify_token(token: str) -> User:
3. require_auth — apps/backend/src/auth/decorators.py — high
4. JWT_SECRET — apps/backend/src/config.py — medium
…You correct the model a few times across sessions: "use single quotes here, not double — we don't use double in this codebase." After enough reinforcements, β3 detection promotes a candidate:
$ cvc cvhub memory pending
Pending β3 candidates (1) for workspace ./my-repo:
[42] "Use single quotes for strings, not double"
5 reinforcements, confidence 1.00
Pattern: style:single-quotes
Use `cvc cvhub memory accept <id>` to promote, `cvc cvhub memory reject <id>` to dismiss.Accept it; future turns see it in the invariants block.
Mid-session, the model itself notices something stable. It invokes
cvhub_remember. You see a permission prompt; you accept. The fact lands
in the invariants block on the next turn.
That's the v0.2.0 walkthrough. The conversation has a position; the workspace has memory; the model participates rather than searching cold.
Key concepts
The anchor
The anchor is the conversation's position in your codebase — a weighted
symbol set. It populates from user mentions (each symbol you reference adds
weight 1.0) and from cv_* tool results (capped at 2.0 total per call so
30-result subgraph calls don't wash out the anchor). Entries decay with a
5-day half-life and prune below the 0.01 weight threshold on session start.
At ≤200 entries the anchor grows freely; past 200 it prunes to top 100 by
weight (hysteresis prevents churn).
Anchor state persists per-workspace in
$XDG_DATA_HOME/cv-code/<workspaceId>/state.db.
Workspace memory
Four solidification mechanisms:
| Source | How it lands | Configurable |
|--------|--------------|--------------|
| β1 (user) | cvc cvhub memory add "fact" [--always] | — |
| β2 (repo) | Auto-extracted on cvc cvhub memory refresh from pyproject.toml, .editorconfig, tsconfig.json, .python-version / .nvmrc / .ruby-version / .tool-versions, .prettierrc | mtime-skip on unchanged files |
| β3 (consolidation) | Detector scans trajectory log; promotes pattern at threshold (default 5 reinforcements) → pending_review queue | threshold, autoAccept, cooldownDays |
| model | cvhub_remember tool with user-confirmation prompt | requireConfirmation |
Active facts surface in the invariants block at the top of every system
prompt. Two tiers per fact: ALWAYS RELEVANT (is_always_included=1,
trimmed only by alwaysIncludeBudgetTokens) and CURRENTLY RELEVANT
(anchor-overlap-ranked, fits remaining budget).
Conflict resolution: β1 > β2 > model > β3. When a new fact would cover an existing higher-priority fact, the new fact is suppressed. When a model fact covers a pending β3 candidate, the β3 candidate gets auto-superseded.
Inspection
cvc cvhub status # at-a-glance state (human / --json / --tui-format)
cvc cvhub anchor # current anchor entries with decay-applied weights
cvc cvhub memory # active facts grouped by source
cvc cvhub memory pending # β3 candidates awaiting review
cvc cvhub memory why <id> # source detail + trajectory evidence
cvc cvhub inspect-prompt # what the model sees this turn (--components for sections)
cvc cvhub inspect-tools # full tool list visible to the modelConfiguration
opencode.json:
{
"cvhub": {
"owner": "your-org",
"repo": "your-repo",
"url": "https://api.hub.controlvector.io", // optional; default
"anchor": {
"halfLifeHours": 120, // 5-day decay (default)
"capHigh": 200,
"capLow": 100,
"weightThreshold": 0.01
},
"memory": {
"invariants": {
"budgetTokens": 2000, // total across both tiers
"alwaysIncludeBudgetTokens": 1000 // sub-budget for ALWAYS tier
},
"consolidation": {
"threshold": 5, // β3 promotion reinforcements
"autoAccept": false, // skip pending_review (not recommended)
"cooldownDays": 30 // after rejection
}
},
"phase": {
"boostPatterns": {
"debug": ["test_*", "*_test.py", "*.spec.ts", "logs/", "errors/"],
"deploy": ["Dockerfile", "*.yaml", "ci/", "deploy/", "infra/"],
"explore": [],
"implement": []
}
},
"ui": {
"statusLine": "always" // always | active-only | hidden
}
}
}All fields have env var equivalents (e.g. CV_CVHUB_ANCHOR_HALF_LIFE_HOURS,
CV_CVHUB_MEMORY_CONSOLIDATION_THRESHOLD). See
docs/cv-hub-integration.md for the full
reference.
Migrating from v0.1.x
Nothing breaks. v0.2.0 is additive across the board.
- v0.1.7 → v0.2.0: README + docs rewrite + consolidated design doc; no code behavior change; no schema change.
- v0.1.0 → v0.2.0: anchor + memory features activate as you use cvc; legacy flat-ranking working-set renders until the anchor populates; no migration command needed.
- Existing
opencode.jsonconfigs continue to work. Newcvhub.anchor/cvhub.memory/cvhub.phasesections are all optional with sensible defaults. - Existing per-workspace state.db files gain
anchor_stateandcvhub_memorytables on first session start (via CREATE TABLE IF NOT EXISTS). No data migration; old tables preserved.
What's next (v0.2.x and v0.3.0+)
A handful of ergonomic improvements are tracked in the CV-DEVIATION ledger and land in patch releases:
- session-end auto-trigger for β3 consolidation (today: manual
cvc cvhub memory consolidate) - always-reject-for-session reply type for
cvhub_remember(today: per-call reject) - animated highlight for newly-promoted β3 candidates (today: static
(N!)indicator) - graph-resolved region label in status line (today: derived from raw symbolId)
Looking further out (v0.3.0+):
- LLM-driven β3 inference for corrections that don't match the pattern rules
- CVHUB.md team-shared facts checked into the repo
- Cross-workspace pattern sharing
- More cv-git query patterns
Upstream relationship
cv-code is a fork of anomalyco/opencode,
maintained as a downstream with v0.2.0's architectural extensions. We pull
upstream changes periodically; see
docs/upstream-deviations.md for the
running list of 46 intentional deviations (per-feature CV-DEVIATION entries
spanning Sprints 1-20).
Architecture
For the design rationale and the 23-choice locked architecture, see
docs/design/cv-arch-cvcode-002-v0.2.0-design.md.
The v0.1.0 predecessor design lives at
docs/design/cv-arch-cvcode-001-v0.1.0-design.md.
For the daily-use guide and full CLI reference, see
docs/cv-hub-integration.md.
For the v0.2.0 announcement post and real-use eval data, see
docs/announcements/v0.2.0.md and
docs/eval-v0.2.0.md.
License
Same as upstream opencode (MIT).
