> ## Documentation Index
> Fetch the complete documentation index at: https://docs.basemode.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# What's new in base 0.16.0

> Why 0.16.0 is a different base, what you see in the first sessions after the update and how to undo any of it, then each big change with an example of what you and Claude now see.

0.16.0 changes how base decides what to put in front of Claude, and it shows you every one of those decisions. base now measures what it sends, ranks it, loads rules for the file being worked on, tells Claude about anything it had to hold back, and turns your corrections into rule changes that you approve.

If you are coming from 0.15, start with [Upgrading from 0.15](#upgrading-from-0-15). The rest of the page takes the big changes one at a time, each with an example of what you and Claude now see. Every example is real output from base 0.16.0, run on a small made-up workspace with a `billing` project and a `web` project. Paths are shortened.

## Why 0.16.0 is a different base

In 0.15, when a prompt matched a domain's keyword, base printed that domain's rules. If the text was longer than Claude Code accepts from a hook, Claude Code cut it at its limit, and nothing told you or Claude what was lost. A rule arrived because a word matched, whether or not it fit the work. A rule that was wrong, or never arrived, stayed that way until you noticed and fixed it by hand.

0.16.0 changes three things.

**Nothing is dropped without a word.** base measures its text before printing it and fits it to a budget in bytes, the size Claude Code was measured to deliver whole. When something does not fit, base leaves out whole rules, least important first, and says what it left out and which command prints it. Rules that do not fit still reach Claude as a short title, with an instruction to read them before acting.

**The right rules for the work.** Rules are ranked by how well they fit the prompt. The file being read or edited decides which project's rules load. A rule can name its own words, folders, tools and commands, and carry test prompts that prove it fires where it should.

**Your corrections improve your rules.** base notices when you correct Claude and asks Claude to file the correction as a proposal. Nothing changes until you approve it. You can see what base matched for every prompt and why, and `base doctor` tells you which rules never fire, fire too often, or keep getting corrected.

<h2 id="upgrading-from-0-15">
  Upgrading from 0.15
</h2>

Getting 0.16.0 can take one command on an older install. After that there is nothing to run, for you or for your Claude. The update backs up every file before it changes it, and every change comes with the command that undoes it.

### How you get it

If base updates itself on your machine, 0.16.0 arrives on its own. A session start finds the release and installs it in the background, and the next session runs it.

Most 0.15 installs do not update themselves. The base installers from 0.7.0 to 0.15.2 turned developer mode on for everyone, and base does not update itself while developer mode is on. Those installs show a weekly "base update available" banner instead. Run this once:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base update
```

0.16.0 turns that installer setting off, so later updates arrive on their own.

### Your first session

The first session on 0.16.0 opens in the new layout described under [Session start](#session-start). Behind it, base starts a one-time tidy of your base data and settings and does not wait for it, so that start is no slower. Near its end, one line says base rewrote its own section of your `~/.claude/CLAUDE.md`:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
[contract] refreshed the BASE CLI section of ~/.claude/CLAUDE.md to this release.
```

Everything in that file outside base's section stays byte for byte. base also adds a SessionEnd entry to `~/.claude/settings.json`, after a backup, keeping every other entry. It tells base which sessions ended, so the rule pass described under [When you correct Claude](#when-you-correct-claude) knows what to read.

### Your second session

The second session tells you what changed. If your `~/.base-gbl/base.toml` still has the line the 0.15 installer wrote, it opens with this paragraph, and Claude is asked to show it to you word for word before anything else:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
base 0.16.0 turned developer mode off. The 0.15 installer turned it on for everyone, so Claude ended every reply with a DEVMODE block listing which of your domains base loaded and why. To see what base adds without the block, run `base log matches`. To turn developer mode back on, run `base config set devmode.enabled true` (while it is on, base does not update itself). To undo this change, run `base doctor --restore "~/.base-gbl/base.toml.BAK-20261006-084252-pre-0.16.0"`.
```

If you turned developer mode on yourself, it stays on and this paragraph does not appear.

After your reminders and handoffs come a few plain sentences per change, each with its undo. These four are from a workspace the 0.15.2 installer set up:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
base 0.16.0: Claude now gets up to 4,000 characters of your saved notes when a session starts. An old setting from the 0.15 installer held them, with a few other items, to 2,000. To set a lower limit again, run `base config set budget.memory_chars 2000`.
base 0.16.0: Your *handoff and *base commands in your global commands.toml now have this version's text. You had not changed them from what an older base shipped, so nothing of yours was lost. To undo it, run `base doctor --restore "~/.base-gbl/commands.toml.BAK-20261006-084249-pre-0.16.0"`.
base 0.16.0: Your rules tied to folders and files now spell out the whole path (1 in this workspace's domains.toml), so `notes` is now `~/work/notes`. They cover the same places as before. To undo it, run `base doctor --restore "~/work/.base/domains.toml.BAK-20261006-084249-pre-0.16.0"`.
base 0.16.0: The rules of `workspace-wide` tied to `~/work` now load for files in that folder that sit outside the 2 projects in it. 0.15 ignored a folder that held more than one project. To narrow them, run `base domain paths --suggest`.
```

You see only the lines that apply to you. When base finds entries in a workspace's data that belong to another of your workspaces, a line like these says how many it moved and where they went.

The third session says nothing more about the update. `base doctor` keeps showing the developer-mode paragraph for 14 days, in case you missed it.

### What changes, and what stays

What the update can change, and only where it applies:

* **Developer mode**, when the 0.15 installer turned it on. Claude stops ending every reply with a DEVMODE block.
* **Your saved notes at session start** get up to 4,000 characters instead of 2,000.
* **Folder rules** are written out with their whole path, so they cover the same place from any folder you start in. A rule on a folder that holds two or more of your projects now loads for files in that folder outside those projects. 0.15 silently ignored such rules.
* **Starter commands you never edited** (`*base`, `*handoff`, `*fork`, `*end`) get this version's text.
* **Your base data is tidied.** Entries that belong to another of your workspaces move back there, or into a separate file in this workspace when base cannot find that one, so nothing is lost. A correction that names exactly one entry is linked to it. Small mix-ups in how entries point to the ones they replace are fixed, repeated lines are removed, and only the newest 3 graph backups are kept.
* **Claude Code's files**: the SessionEnd entry and base's own CLAUDE.md section, as above.

What stays as it was:

* Every rule, decision, note, handoff, fork, project, task and reminder you have. An entry may move to the workspace it belongs to, but none is deleted.
* A starter command you edited. If it is your `*base` and still has the old `rule add` line, session start says so once.
* Developer mode, if you turned it on yourself.
* Everything in `~/.claude/CLAUDE.md` outside base's section, and every other entry in `~/.claude/settings.json`.

### Undoing it

Each line above ends with its own undo. `base doctor --restore <path>` puts back a backup base made, either a graph snapshot or a `*.BAK-<date>-pre-<version>` copy beside a config file, and refuses any other file, so it cannot overwrite something base did not write.

To turn developer mode back on:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base config set devmode.enabled true
```

To turn off every change in the first list except the two in Claude Code's files, set this before your first session on 0.16.0:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base config set graph.auto_migrate false
```

<Note>
  One case needs a person. If you renamed a workspace folder after base wrote data for it, its older entries stay under the old folder name. `base doctor` explains what it found and leaves them alone, because only you can say whose data it is.
</Note>

More detail: [Updating base](/guides/updating), and the [0.16.0 changelog entry](/changelog#0-16-0).

## What base adds to each message, and what it holds back

Every prompt you send can carry text from base: rules matched to your prompt or to a file the session touched, that domain's context, relay messages, your global rules and decisions, and bracket rules, in that order of importance. 0.16.0 builds this text as named blocks and measures it in bytes against a budget, `[budget] prompt_bytes`, which is 10,000 bytes by default. That is the size measured to arrive whole on Claude Code 2.1.287. Inside a block, rules are ranked by how well they fit the prompt: shared words count, and rare words count more. Keywords and folders still decide which rules are served; the score only decides their order.

Here is the start of what Claude gets for the prompt "the invoice total is a float, fix the button that shows it". The numbers are each rule's place in its domain; the order is the ranking, so the rule about floats comes first:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
[DOMAIN: billing]
  0. Store money as whole cents in an integer, never as a float.
  4. An issued invoice is never edited. To change one, issue a credit note against it and a new invoice, so the audit trail shows both.
  5. Discounts are stored as their own negative line with a reason code, never folded into a line's unit price, so reports can total them.
  7. Rounding happens once per line, half to even, after quantity times unit price and before tax; never round a running total.
```

This workspace also has 59 global rules, more than fit in 10,000 bytes. base prints the best-ranked ones whole and holds the rest back, weakest first. It never cuts a rule in the middle. The output then ends like this (shortened):

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
[base: withheld 30 of 59 global-rules (7,556 bytes) over [budget] prompt_bytes = 10000 · full text: base hooks show global-rules]

[base: 30 rules for this message did not fit in its 10,000-byte limit. They still apply: before you act on anything a title below covers, run the command above the title and read the rule in full.]
base hooks show global-rules
  29. Do not add a cache without a way to clear it.
  30. Validate input at the edge of the system.
  31. Use the shared HTTP client, never a raw socket.
  32. Every alert names the runbook that answers it.
  33. Never print a secret, even in a test.
  ...
  52. Return errors, do not panic, in library code.
and 6 more without a title: base hooks show global-rules (6)
```

Claude now knows what it is missing and how to read it. A rule held back is not marked as seen, so a later prompt in the same session can still deliver it in full. Every other rule arrives once per session: base keeps track of each rule Claude already has, so a domain that matches again does not repeat it.

To see the blocks of your last prompt, and print any of them in full:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base hooks show
base hooks show global-rules
```

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
Prompt blocks of session 5e55a1d0-… at 2026-10-06T09:01:05-05:00 ([budget] 10000 bytes), in output order:
  billing-rules  priority 1  12 rules  1,549 bytes  printed
  web-rules  priority 1  1 rule  77 bytes  printed
  global-rules  priority 4  59 rules  14,367 bytes  printed, 30 of 59 withheld
```

Session start works the same way, with its own budget, `[budget] session_start_bytes`. Both write their full, untrimmed text to `.base/hook-output/<session id>/`, so each session has its own copy.

**When your Claude Code changes.** The budgets were measured on one version of Claude Code. `base doctor` compares that version with the one you run and tells you when to measure again:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
⚠ [budget] measured_on is 2.1.287; this host runs 2.1.291 · run base doctor --measure
```

`base doctor --measure` asks Claude Code, with a few headless calls on a cheap model, how much of each hook's text actually reaches the model, then writes the budgets. Nothing runs it for you, because it spends model calls.

More detail: [Debugging injection](/guides/debugging-injection), [Context reference](/reference/context), [Config and secrets](/guides/config-and-secrets).

## Rules follow the file you touch

When Claude reads, edits or writes a file, or a shell command names one, base finds the deepest registered project folder that holds that file and loads that project's rules. No trigger needed. The rules of other projects stay out.

In the example workspace, Claude edits `web/src/button.tsx`. Beside that edit, Claude sees the `web` project's rule. base matched only the `web` project, as the log below shows:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
[FILE MATCH: web]
  0. Use the shared Button component; never style a raw button.
```

Earlier in the same session, Claude read `billing/src/invoice.rs` and base printed nothing at all, because the prompt before it had already delivered the billing rules. `base log matches` shows both, and why:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
09:01:04  prompt  GLOBAL(always) billing(keyword: invoice)  served 42  cut 31  "how do I refund an invoice that was paid..."
09:01:04  file    billing(path)                         served 0  cut 0  .../src/invoice.rs
09:01:04  file    web(path)                             served 1  cut 0  .../src/button.tsx
```

**A rule can say when it matters.** A rule with no matchers of its own is served through its domain, as before. A rule can also carry its own:

* `--keywords "refund, refunds"` (or `--words`): served when the prompt has one of these words.
* `--place <folder or file>` and `--path <file or folder>`: served for work in that place.
* `--tool <name>` and `--command "<command>"`: served when Claude is about to use that tool or run that command, at most once every 10 minutes per session.

The `cut 31` on the first row above is the 30 global rules held back for space, plus one rule with a word of its own, `currency`, which was not in the prompt.

A project inside another one can carry its parent's rules: `base project update <slug> --parent <slug> --nested true`. Work in the child then loads the parent's rules too, after its own.

**Rules carry test prompts.** `--fires-on "<prompt>"` names a prompt that must serve the rule, and `--quiet-on "<prompt>"` one that must not. `base rule test` runs them through the same matching the prompt hook uses:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base rule add --domain billing --text "Currency codes are ISO 4217, in upper case." --keywords "currency" --fires-on "which money format do we use"
base rule test
```

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
billing.2731db7c   ok 1 fire · ok 1 quiet   "Refunds go through the payments queue, never straight to th…"   scores: fires 8.76 · quiet 0.00
billing.945303c3   "Currency codes are ISO 4217, in upper case."
  MISS        "which money format do we use"   score 0.00
              topic score 0: no word of its own, of its text or of its domain's keywords is in the prompt (minimum 0.75)
scores: BM25, each fires-on prompt held out of its own rule; [match] min_score is unset, so the tests are judged by keyword only
2 rules tested, 1 miss, 0 false fires
rules with no tests, per domain (untested of total):
  GLOBAL   59 of 59
  billing  12 of 14
  web      1 of 1
```

The test caught a real gap: someone asking about the "money format" never says "currency". A rule's keywords change through a proposal you approve, so the fix goes through the same review as a correction (next section):

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base rule propose --rule billing.945303c3 --keywords "currency, money" --example "which money format do we use"
base rule review --approve p-0002
base rule test --rule billing.945303c3
```

The approval replays the change over your recent prompts first, and the test now passes:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
approved p-0002: words "currency", "money" added to rule billing.945303c3, in graph (workspace tier)
  replay 0.0%
  rule tests, billing: 2 rules tested, 0 misses, 0 false fires · base rule test --domain billing
billing.945303c3   ok 1 fire   "Currency codes are ISO 4217, in upper case."   scores: fires 4.05
```

Inside a Claude Code session, `base rule add` refuses a rule without keywords and a `--fires-on` prompt, so every rule Claude adds arrives with its first test.

**Projects know their folder.** `base project paths --suggest` lists every project whose folder is missing or too broad and suggests the right one, and `base project rename <old> <new>` renames a project and its domain everywhere, keeping the old name working.

More detail: [Rules and domains](/guides/rules-and-domains), [Domains and triggers](/how-it-works/domains-and-triggers), [Tiers and scoping](/how-it-works/tiers-and-scoping), [Projects and tasks](/guides/projects-and-tasks), [Standards](/guides/standards).

## When you correct Claude

In the example session, Claude got the refund rule on the first prompt and answered wrongly anyway. The next prompt is a correction:

> no, that's wrong. refunds never call the card API directly

base reads the wording, and that prompt carries one extra line for Claude:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
This may be a correction. If it is, run base rule propose --from-turn after answering.
```

Claude answers you first. Because it read the whole exchange, it can tell whether this was a correction, and if it was, it files it:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base rule propose --from-turn
```

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
proposal p-0001 · rewrite · rule billing.2731db7c
  why: served to this session, and corrected anyway
  now: Refunds go through the payments queue, never straight to the card API.
  new text: none given; the marker line says what was wrong
  keywords: directly, refunds, call, card (suggested from the prompt; --keywords chooses)
  example, its first fires_on test: "no, that's wrong. refunds never call the card API directly"
  marker: CORRECTED: I sent the refund straight to the card API; refunds go through the payments queue.
  pending review: base rule review (p-0001). Wrong kind or target? Run it again with --rule <domain>.<id>, --decision <slug> or --new: this turn's proposal is replaced.
```

(Two lines, the evidence and the closest candidates, are left out here.) base sorted it as a **rewrite**: Claude had the rule and did the wrong thing, so the wording needs work. A correction about a rule that was never served is a **keyword gap**, and one that no rule covers is a **new rule**.

The `CORRECTED:` line is Claude's own. `base install` offers to add one line to `~/.claude/CLAUDE.md` asking Claude to start a corrected reply that way. If you decline, session start carries the line instead.

Nothing changes until you say so. Your next session start says:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
rule proposals: 1 pending · base rule review
```

`base rule review` walks the proposals with one key each: `a` approve, `e` edit, `r` reject, `s` skip, `q` stop. Before you approve a change, base replays it over your recent prompts and shows which would start or stop serving the rule; `base rule replay` runs the same check by hand. A change that would fire on more than a quarter of them is flagged TOO BROAD and needs `--broad-ok`. A proposal you reject is never made again.

**The rule pass.** `base tune` reads the sessions since its last pass and proposes keyword fixes, new rules, merges, splits and retirements, judged by a cheap model with its answers cached. It never runs inside a hook. When a pass is due, the next prompt says so. `base tune --dry-run` shows what it would read.

**Shadow mode.** `base shadow start` runs a different matcher beside the live one on every prompt and file touch, while only the live one's choice is printed. `base shadow report` shows where they differ and whether your corrections favour the candidate.

More detail: [Corrections and tuning](/guides/corrections-and-tuning), the new guide for all of this.

## Doctor and the match log: seeing what base did

`base log matches` shows every prompt and file touch: which domains matched and by what, how many rules were served, and how many matched but were held back or left out, as in the rows above. `--json` adds each rule's id, score and reason. The rows live in `.base/match-log.jsonl` for 90 days. Prompt text is kept with secrets such as API keys, tokens and passwords replaced, and `[log] prompt_text` keeps less if you want.

`base log corrections` shows what base read as a correction, in a session or a whole transcript.

`base doctor` now reports what each hook printed against its budget, and adds a section on how your rules are used, read from the match log. On the example workspace it says:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
─── rules and decisions, from the match log ───
   match log: 1 day (since 2026-10-06) · 4 typed prompts, 0 task notifications · 0 with no text
   dead (not served in 30 days): not judged yet · the match log covers 1 day, fewer than [doctor] dead_days = 30
   noisy: not judged yet · 4 typed prompts in the last 30 days, fewer than 100
   ignored (corrected after 3+ times, and after at least twice the log average of 37% of servings): 0
   review (served 20+ times, unchanged 60+ days): 0
   held back for space (matched a message but did not fit in its 10,000-byte limit, last 30 days): 30
     GLOBAL.a29c6027 "Write the rollback step before the deplo..."   held back 2 times, in full 1 time · 254 bytes · it is in GLOBAL, so every session gets it: if it is about one project, move it to that project's domain, or shorten it to one or two sentences (base rule list --domain GLOBAL shows it)
```

Under the last line it names the rules held back most often (the first of ten is shown here), each with what to do about it. As the log grows, it also names rules that never fire, domains that fire on more than a quarter of your prompts, and rules that keep getting corrected. This section is advice: it never changes doctor's verdict.

`base doctor --fix` prints a plan for repairing what doctor reports and changes nothing; `base doctor --fix --yes` applies it after a snapshot. It is the same repair the update runs.

`base --version` now names the commit it was built from, for example `base 0.16.0 (build 1a2b3c4d5e6f)`, so two builds of one version can be told apart.

More detail: [Graph health](/guides/graph-health), [Debugging injection](/guides/debugging-injection), [Setup reference](/reference/setup).

## Session start

Session start has a new layout: one header line, a short instruction block for Claude, then what is due, your handoffs, forks, projects, tasks and milestones, and then the rest. From the example workspace:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
[BASE START · 2 due · handoffs 1 open (1 shown) · forks 0 · projects 2 · tasks 0 · milestones 0 · withheld 0 · full: ~/work/.base/hook-output/<session id>/session-start.md]
...
DUE NOW (2) · all: base reminder list
  1 renew the TLS certificate · archives 2026-10-08 unless snoozed: base reminder snooze 1 <duration>
  2 send the March invoices

HANDOFFS (1 open, newest 1 shown) · all: base handoff list
  A) billing · handoff-refunds · 0d
```

DUE NOW is always on the first screen, and the counts in the header and in each block agree. Reminders are numbered and handoffs are lettered, so you can act on what you see:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base reminder snooze 2 1d
base handoff show A
```

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
DUE NOW 2 is 'send-the-march-invoices' (session start at 2026-10-06T09:01:03-05:00)
Reminder 'send-the-march-invoices' snoozed (workspace tier)
doc: ~/work/billing/handoff-refunds.md
handoff: handoff-refunds · project billing · workspace tier · 0d
matched: letter A from the session start at 2026-10-06T09:01:03-05:00
```

`base handoff show` also takes a slug, a project name or a few words. Each session reads its own letters, so another session's start does not change what yours point at.

Your saved notes have their own budget of 4,000 characters, filled with whole notes only, and the block ends with how many were left out. Tasks and milestones from both your workspace and the global tier are listed, and the block says which data it read, so an empty list is never mistaken for missing data.

More detail: [Handoffs and forks](/guides/handoffs-and-forks), [Sessions reference](/reference/sessions), [Where things live](/how-it-works/where-things-live).

## Relay

0.15 pasted the whole relay watcher script into prompts and tool calls. 0.16.0 sends one line instead, and only to a session whose relay title is in use, meaning it sent or received a ping or registered by hand:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
relay: billing-desk has no inbox watcher · run base relay arm and start the Monitor it prints
```

`base relay arm` prints exactly what to start. Relay messages read as information, never as orders that outrank you, and each one is shown once.

A ping now reaches the session it was sent to. When a title passes to a new session, the old session's undelivered pings are archived and each sender is told who holds the title now. A ping that waits more than a day undelivered is archived the same way. The inbox watcher base ships no longer drops pings when more than five are waiting.

More detail: [Multiple sessions](/guides/multiple-sessions), [Sessions reference](/reference/sessions).

## Reminders, handoffs and deferred work

Reminders can be snoozed, archived and brought back: `base reminder snooze <number or slug> <duration>`, `base reminder archive`, `base reminder unarchive`, and `base reminder list --archived`. All of them work across your workspace and the global tier.

An overdue reminder warns before it archives itself. From 8 days overdue, its line says when it will go, as on the certificate reminder above. It archives itself only when it is 10 or more days overdue and that warning was first shown at least 2 days earlier, and the next session start says so once with the command that brings it back. It is kept, never deleted.

A new handoff archives only the earlier one in its own lane: the earlier one by the same author, or in the lane you name with `--lane`. Several sessions on one project no longer archive each other's handoffs. `base handoff unarchive <slug>` and `base fork unarchive <slug>` undo an archive. A handoff, fork, decision or note written from a folder inside `~/.base-gbl` now goes to the workspace around that folder, not the global tier, and opening a handoff or fork doc counts as activity on it.

**Deferred work** is off until you turn it on with `[defer] enabled = true`. Then handoffs, forks, tasks and milestones nobody touched for 10 days (set per kind in `[defer.days]`) stop showing at session start and stay listed. `base handoff deferred`, `base fork deferred`, `base task deferred` and `base milestone deferred` list them, each with the command that brings it back. `base reconcile --dry-run` shows what a pass would defer before you turn it on.

More detail: [Handoffs and forks](/guides/handoffs-and-forks), [Projects and tasks](/guides/projects-and-tasks), [Star commands](/guides/star-commands).

## Sync and the code map

**One bad file no longer stops a sync.** A file whose frontmatter holds a value the graph cannot store used to end the whole sync before anything was written. Now base skips that file, names it, writes every other file, and exits with code 3:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base sync
```

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
base sync skipped notes/bad-frontmatter.md: its relatedTo value "pay>ments" cannot be stored in the graph. Change that value in the file, then run base sync again.
Sync partial: 3 scanned, 2 extracted, 0 skipped. 1 file was not synced (named above); the graph still has what it held for it before. Fix it, then run base sync again.
```

Exit code 0 is still a complete sync and 1 a failed one. A script that treats any non-zero code as a failure should read 3 as "written, with the files named".

**Code maps.** A code-map build base starts on its own stops after 15 minutes, with everything it started, and the next session start says so. A tree that needs longer can be built by hand with `base sync --ast --yes --no-time-limit --target <folder>`. The hint to use `base ast query` now appears only for a search of source code in a mapped app, and never tells you to map an app base maps by itself.

Fixed from reports: [`[[wikilinks]]` in frontmatter lists](https://github.com/ChristopherKahler/base/issues/162) extract cleanly, [`sync.exclude` holds through links](https://github.com/ChristopherKahler/base/issues/164) such as symlinks and junctions, [a pnpm workspace that lists its own root](https://github.com/ChristopherKahler/base/issues/172) maps, and [a file name with a character like `→`](https://github.com/ChristopherKahler/base/pull/166) no longer breaks session start.

More detail: [Navigating code](/guides/navigating-code), [Ingesting documents](/guides/ingesting-documents), [Code reference](/reference/code), [The graph](/how-it-works/the-graph).

## Where to read more

Every page below was updated for 0.16.0.

<CardGroup cols={2}>
  <Card title="Corrections and tuning" icon="sparkles" href="/guides/corrections-and-tuning">
    New in 0.16.0: how base notices a correction and turns it into a rule change you approve.
  </Card>

  <Card title="Rules and domains" icon="list-check" href="/guides/rules-and-domains">
    Matchers of a rule's own, test prompts, and the file you touch.
  </Card>

  <Card title="Debugging injection" icon="bug" href="/guides/debugging-injection">
    What base sent, what it held back, and why.
  </Card>

  <Card title="Updating base" icon="arrow-up" href="/guides/updating">
    What the update changes by itself, and how to undo it.
  </Card>
</CardGroup>

**Getting started:** [Installing base](/install) · [Coach mode](/coach-mode)

**How it works:** [Overview](/how-it-works) · [The graph](/how-it-works/the-graph) · [Domains and triggers](/how-it-works/domains-and-triggers) · [Tiers and scoping](/how-it-works/tiers-and-scoping) · [Where things live](/how-it-works/where-things-live)

**Guides:** [Star commands](/guides/star-commands) · [Handoffs and forks](/guides/handoffs-and-forks) · [Decisions and recall](/guides/decisions-and-recall) · [Projects and tasks](/guides/projects-and-tasks) · [Navigating code](/guides/navigating-code) · [Ingesting documents](/guides/ingesting-documents) · [Multiple sessions](/guides/multiple-sessions) · [Config and secrets](/guides/config-and-secrets) · [Standards](/guides/standards) · [Graph health](/guides/graph-health)

**Reference:** [Commands](/reference/commands) · [Graph and memory](/reference/graph-and-memory) · [Projects](/reference/projects) · [Code](/reference/code) · [Context](/reference/context) · [Sessions](/reference/sessions) · [Setup](/reference/setup)

**Every change, area by area:** the [0.16.0 changelog entry](/changelog#0-16-0).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.