Brain
The Brain subsystem periodically consolidates session memory and re-evaluates long-running context — TUI plugin, server route, and headless scheduler.
Overview
Brain is nikcli's "long-term memory" subsystem. While a session is running, every
tool call, message, and decision lives in the session's JSON store; Brain's job is
to periodically consolidate that signal into a single, well-organised
memory.instruction.md file that future coding sessions can read at
startup to orient quickly.
Brain is implemented in packages/nikcli/src/brain/ and surfaces in three
places: a headless scheduler that ticks every hour, a TUI feature plugin for the
brain model picker, and a server route (/brain) plus a
typed httpapi/brain.ts group for the Studio dashboard and external
clients.
experimental.brain
to true in nikcli.json, or turn on Enable Brain
in Brain Settings.
What Brain does
When triggered, Brain runs a real nikcli session under the hood — but a session with a very narrow scope. It:
- Reads the existing memory file (if any) under
.github/instructions/memory.instruction.md. - Pulls the most recent N sessions (default 10) and formats their message parts into a compact review.
- Sends the prompt
(
Brain.buildBrainPrompt(memoryPath, reviews, currentMemory)) to a dedicated session titledBRAIN_SESSION_TITLE, with permissions restricted to read/edit-only — notask, notodo, nobash. - Cancels the session via
prompt.cancelafterBRAIN_SESSION_TIMEOUT_MS = 5 minutes. - Diff-checks the memory file before/after. If it changed, marks the run as a
success and writes the brain lock file (
Global.Path.state/.brain-lock) so the nextshouldTriggercheck has a fresh anchor.
The consolidating model is configurable through experimental.brainModel
("provider/model"). When the configured model is unknown or unreachable,
Brain silently falls back to the user's default model so the pass still runs.
Trigger conditions
Brain.shouldTrigger() decides whether the scheduler should fire. It
refuses to run when Brain or memory is disabled, when the cooldown has not elapsed,
when a scan has happened in the last SCAN_THROTTLE_MS = 10 minutes, or
when there aren't enough sessions since the last successful Brain pass.
| Constant | Default | Meaning |
|---|---|---|
DEFAULTS.minHours | 24 | Minimum hours between successful Brain passes (configurable via experimental.brainMinHours). |
DEFAULTS.minSessions | 5 | Minimum new sessions since the last pass before Brain fires (configurable via experimental.brainMinSessions). |
SCAN_THROTTLE_MS | 10 * 60 * 1000 | How often shouldTrigger() is allowed to scan session history. |
LOCK_DURATION_MS | 1 hour | Stale-lease duration for the brain flock lock. |
BRAIN_SESSION_TIMEOUT_MS | 5 minutes | Hard ceiling on a single Brain session; cancelled via prompt.cancel on expiry. |
SESSION_REVIEW_LIMIT | 10 | How many recent sessions are included in the prompt. |
SESSION_REVIEW_MAX_CHARS | 12_000 | Per-session review truncation length. |
The scheduler registers itself with
Scheduler.register({ id: "brain", interval: 60 * 60 * 1000, scope: "instance" })
— one tick per hour, scoped to the project instance.
Brain.trigger({ force: true }) skips the
shouldTrigger gate (except for the enabled and
memoryEnabled checks) and reviews the most recent sessions even when
no time has elapsed. The TUI dialog and the /brain/trigger route expose
this path.
Configuration
All Brain knobs live under experimental in
nikcli.json. This example enables Brain:
{
"experimental": {
"brain": true,
"memory": true,
"brainMinHours": 24,
"brainMinSessions": 5,
"brainModel": "anthropic/claude-sonnet-4.5"
}
} | Field | Default | Meaning |
|---|---|---|
experimental.brain | false | Master switch for the Brain subsystem. When false, neither the scheduler nor a manual trigger will fire. |
experimental.memory | true | Whether Brain is allowed to write the memory file. Turning this off keeps Brain's read path active but disables consolidation. |
experimental.brainMinHours | 24 | Override DEFAULTS.minHours. |
experimental.brainMinSessions | 5 | Override DEFAULTS.minSessions. |
experimental.brainModel | (default provider/model) | "provider/model" string the consolidation session runs on. Falls back silently to the user's default model when unavailable. |
Memory file
Brain writes to .github/instructions/memory.instruction.md inside the
project directory (created on demand). The path is the same convention used by
GitHub Copilot for project-level instructions, so the file is shared automatically
with anything in the repo that reads .github/instructions/*.md.
The consolidating prompt focuses on four phases — orient, gather, consolidate,
prune — and explicitly forbids creating a new memory file or asking the user
questions. The full prompt template is in Brain.buildBrainPrompt(); the
resulting memory file is meant to be concise, dated, and indexed for fast lookup.
.github/instructions/, every future
nikcli session in the same project picks it up automatically — it becomes part of
the system prompt context for the next agent run.
TUI & API surface
Brain is reachable from three places: the scheduler (passive), the TUI dialog
(dialog-brain.tsx — pick the model and force a run), and the server
routes.
TUI dialog
Bound to the brain feature plugin and surfaced from the command
palette. Lets you pick the consolidation model and trigger a forced run.
Server routes
GET /brain returns the full status payload (enabled, memory enabled,
min hours, min sessions, last brain at, hours since, sessions since, should
trigger, configured model). POST /brain/trigger accepts
{force: boolean} and runs Brain.trigger.
Typed HttpApi
Same surface under the typed HttpApi group
(operationId: brain.status, brain.trigger) — mounted
through HttpApiBridge when NIKCLI_EXPERIMENTAL_HTTPAPI is
set. Used by the Studio dashboard and SDK clients.
initBrainScheduler() with
scope: "instance". The scheduler definition is in
packages/nikcli/src/scheduler/; one tick per hour, per project
instance.
Source anchors
| Concern | File |
|---|---|
| Core service + consolidation prompt | packages/nikcli/src/brain/index.ts |
| Hourly scheduler | packages/nikcli/src/brain/scheduler.ts |
| Constants | @nikcli-ai/util/brain-constants |
| Classic routes | packages/nikcli/src/server/httpapi/brain.ts |
| Typed HttpApi | packages/nikcli/src/server/httpapi/brain.ts |
| TUI plugin | packages/tui/src/feature-plugins/brain/index.tsx |
| TUI dialog | packages/tui/src/component/dialog-brain.tsx |