> User Manual
Everything you need to know about installing, configuring, and using Bernard.
1. Getting Started
Installation
Bernard requires Node.js 20.9.0 or later. Install it globally from npm:
$ npm install -g bernard-agent
After installation, the bernard command is available globally in your
terminal.
First-Time Setup
On first launch, Bernard runs an interactive setup wizard that walks you through selecting a provider and entering your API key. You can also configure it manually:
# Store an API key
$ bernard add-key anthropic sk-ant-...
# Verify it's configured
$ bernard providers
Bernard follows the XDG Base Directory Specification. Default locations:
-
~/.config/bernard/—preferences.json,keys.json(0600),.env,mcp.json -
~/.local/share/bernard/—memory/,rag/,routines/,specialists/,tool-profiles/,cron/ ~/.cache/bernard/— embeddings models, update-check cache-
~/.local/state/bernard/— conversation history, logs, daemon PID
Override with the standard XDG_*_HOME variables, or use
BERNARD_HOME=/path to force the legacy flat layout (everything under one
directory, like the old ~/.bernard/). On first run, files are auto-migrated
from ~/.bernard/ if present.
Basic Usage
Launch the REPL by running bernard with no arguments. Type natural-language
requests and Bernard will use its tools to help you:
$ bernard
bernard> what git branch am I on?
▶ shell: git branch --show-current
You're on the main branch.
Type /help to see available slash commands, or /exit (or
Ctrl+C) to quit.
CLI Flags
| Flag | Description | Example |
|---|---|---|
-p, --provider |
Override the LLM provider | bernard -p openai |
-m, --model |
Override the model name | bernard -m gpt-4o |
-r, --resume |
Resume the previous conversation | bernard -r |
--alert <id> |
Open with a cron alert context | bernard --alert abc123 |
-V, --version |
Show version number | bernard -V |
Resuming Conversations
Use the -r flag to pick up where you left off. Bernard saves conversation
history to disk between sessions and replays it on resume. A session boundary marker is
injected so the agent knows prior tasks are considered complete.
$ bernard -r
# Previous conversation is restored
2. Configuration
Environment Variables
| Variable | Description | Default |
|---|---|---|
BERNARD_PROVIDER |
Default LLM provider | anthropic |
BERNARD_MODEL |
Default model name | Provider-specific (first in list) |
BERNARD_MAX_TOKENS |
Max tokens per AI response | 4096 |
BERNARD_SHELL_TIMEOUT |
Shell command timeout (ms) | 30000 |
BERNARD_TOKEN_WINDOW |
Context window size for compression (0 = auto-detect) | 0 |
BERNARD_MAX_STEPS |
Max agent loop iterations per request | 25 |
BERNARD_RAG_ENABLED |
Enable/disable RAG memory | true |
BERNARD_CRITIC_MODE |
Enable critic mode for response verification | false |
BERNARD_AUTO_CREATE_SPECIALISTS |
Auto-create specialists above confidence threshold | false |
BERNARD_AUTO_CREATE_THRESHOLD |
Confidence threshold for auto-creating specialists (0–1) | 0.8 |
BERNARD_REACT_MODE v0.9.0+ |
Coordinator (ReAct) mode —
think → act → evaluate → decide loop.
Per-turn step budget grows to min(BERNARD_MAX_STEPS × 3, 150).
|
false |
BERNARD_PROMPT_REWRITER v0.9.0+ |
Pre-turn LLM pass that rewrites the user message for the active model family (fail-open) | true |
BERNARD_REFERENCE_LOOKUP v0.9.0+ |
When the resolver returns unknown, attempt one read-only tool lookup
before prompting (5 s timeout, fail-open)
|
true |
BERNARD_LOOKUP_TOOLS v0.9.0+ |
Comma-separated tool-name allowlist additions for the resolver lookup pass (use read-only tools only) | — |
BERNARD_TOOL_DETAILS v0.9.0+ |
Show full tool-call input/output (off collapses each call to a one-line summary) | true |
BERNARD_SUBAGENT_RESULT_MAX_CHARS
v0.9.0+
|
Max characters returned from a sub-agent / specialist into the parent agent's context (the user still sees full output) | 4000 |
BERNARD_PLAIN_MENU v0.9.0+ |
Force the classic numbered-list menu fallback instead of the arrow-key UI (also used automatically in non-TTY shells) | 0 |
BERNARD_CORRECTION_ENABLED v0.9.0+ |
Run the correction agent at session close to learn from tool-wrapper failures | true |
BERNARD_HOME |
Override every XDG directory with one flat path (legacy ~/.bernard/
layout)
|
— |
BRAVE_API_KEY |
Optional — Brave Search API key for web_search |
— |
TAVILY_API_KEY |
Optional — Tavily API key for web_search (fallback when Brave
is absent)
|
— |
ANTHROPIC_API_KEY |
Anthropic API key | — |
OPENAI_API_KEY |
OpenAI API key | — |
XAI_API_KEY |
xAI API key | — |
Custom providers (see Custom Providers)
store their keys via bernard add-key <name> <key> and are
not read from environment variables — there is no
BERNARD_<NAME>_API_KEY bridge.
.env File Loading
Bernard loads environment variables from .env files in this priority order:
-
Current working directory —
./.env(checked first) -
XDG config —
$XDG_CONFIG_HOME/bernard/.env(defaults to~/.config/bernard/.env) -
Legacy —
~/.bernard/.env(fallback for migrations from older installs)
API keys stored via bernard add-key take precedence over
.env values.
API Key Management
# Add a key
$ bernard add-key anthropic sk-ant-...
# Remove a key
$ bernard remove-key anthropic
# Check key status for all providers
$ bernard providers
Keys are stored in $XDG_CONFIG_HOME/bernard/keys.json (defaults to
~/.config/bernard/keys.json) with file permissions set to 0600
(owner read/write only).
Options Management
Configurable options can be viewed and changed from the CLI or within the REPL
(/options):
| Option | Env Var | Default | Description |
|---|---|---|---|
max-tokens |
BERNARD_MAX_TOKENS |
4096 | Maximum tokens per AI response |
shell-timeout |
BERNARD_SHELL_TIMEOUT |
30000 | Shell command timeout in milliseconds |
token-window |
BERNARD_TOKEN_WINDOW |
0 | Context window size for compression (0 = auto-detect from model) |
max-steps |
BERNARD_MAX_STEPS |
25 | Max agent loop iterations per request. ReAct mode triples this (capped at 150). |
tool-details v0.9.0+ |
BERNARD_TOOL_DETAILS |
true | Show full tool-call input/output (off collapses each call to a one-line summary) |
# List current option values
$ bernard list-options
# Reset a single option to default
$ bernard reset-option max-tokens
# Reset all options to defaults
$ bernard reset-options
Themes v0.3.0+
Bernard comes with six built-in color themes. Switch at any time using the
/theme REPL command. Your choice persists across sessions.
| Theme | Description |
|---|---|
bernard |
Default orange accent theme |
ocean |
Cyan/blue palette |
forest |
Green nature palette |
synthwave |
Purple/pink retro palette |
high-contrast |
Accessibility — maximized contrast |
colorblind |
Accessibility — IBM color-blind safe palette |
3. Providers
Bernard uses the Vercel AI SDK for unified access to multiple LLM providers. All tools, memory, and capabilities work identically regardless of which provider you choose.
Anthropic
Default provider. Set ANTHROPIC_API_KEY or run
bernard add-key anthropic <key>.
Available Models
claude-sonnet-4-5-20250929(default)claude-opus-4-6claude-haiku-4-5-20251001claude-opus-4-20250514claude-sonnet-4-20250514
OpenAI
Set OPENAI_API_KEY or run bernard add-key openai <key>.
Available Models
gpt-5.2(default)gpt-5.2-chat-latesto3o3-minigpt-4o-minigpt-4.1gpt-4.1-minigpt-4.1-nano
xAI
Set XAI_API_KEY or run bernard add-key xai <key>.
Available Models
grok-4-fast-non-reasoning(default)grok-4-fast-reasoninggrok-4-1-fast-non-reasoninggrok-4-1-fast-reasoninggrok-4-0709grok-code-fast-1grok-3grok-3-mini
Custom Providers
A custom provider is a user-registered named endpoint that wraps one of
the three installed SDKs (openai, anthropic, xai)
and points it at a non-default base URL — Ollama, LM Studio, vLLM, OpenRouter, Together,
Fireworks, internal proxies, or anything else that speaks one of those APIs. You can
register as many as you like, and they coexist with the built-ins.
Register one from the command line:
$ bernard add-provider ollama \
--sdk openai \
--base-url http://localhost:11434/v1 \
--model llama3.2 \
--key ollama
The key is required (some local servers ignore the value but the SDK still sends one). If
you skip --key, run bernard add-key ollama <token>
afterwards.
To register interactively, type /provider in the REPL and choose
+ Add custom provider…. The wizard asks for SDK, name, base URL, default
model, and API key in turn.
Other commands:
bernard providers— lists built-ins and custom side-by-side.-
bernard remove-provider <name>— deletes the entry and its stored key. -
/model— for a custom provider, the menu shows the remembered model list plus a + Type a new model name… entry; whatever you type is added to the list for next time.
When the active provider is custom, the welcome banner prints an extra
Endpoint: line so it's obvious the session isn't using the SDK's default URL.
Reserved names: anthropic, openai, xai (the
built-ins). Custom-provider API keys are stored in keys.json alongside the
built-in keys and are not read from environment variables — there is no
BERNARD_<NAME>_API_KEY bridge.
Switching Providers
There are three ways to switch your provider and model:
-
CLI flags —
bernard -p openai -m gpt-4o -
REPL commands —
/providerand/modelfor interactive selection -
Environment variables —
BERNARD_PROVIDERandBERNARD_MODEL
Changes made via /provider and /model are saved to preferences
and persist across sessions.
4. REPL Commands
Type slash commands in the REPL to control Bernard. Tab-completion is supported, and live hints appear as you type.
| Command | Description |
|---|---|
/help |
Show all available commands |
/clear |
Clear conversation history, scratch notes, and the terminal screen |
/compact |
Compress conversation history in-place |
/task |
Run an isolated task with structured JSON output (no history, proportional step budget — minimum 2) |
/memory |
List all persistent memory keys |
/scratch |
List session scratch note keys |
/mcp |
Show MCP server connection status and available tools |
/cron |
Show cron jobs, daemon status, and unacknowledged alerts |
/rag |
Show RAG memory stats, domain breakdown, and recent facts |
/facts |
Show RAG facts currently in the context window |
/provider |
Interactively switch LLM provider; menu ends with + Add custom provider… to register a new endpoint |
/model |
Interactively switch model for the current provider; for custom providers, the menu includes a + Type a new model name… entry that is remembered for next time |
/theme |
Interactively switch color theme |
/update |
Check for and install updates |
/routines |
List all saved routines |
/create-routine |
Create a routine with guided AI assistance |
/create-task |
Create a task routine (task- prefixed) with guided AI assistance
|
/specialists |
List all saved specialists |
/create-specialist |
Create a specialist with guided AI assistance |
/candidates |
Review auto-detected specialist suggestions |
/agent-options v0.9.0+ |
Configure agent behavior — toggles for critic mode, ReAct/coordinator mode, prompt rewriter, tool-details, plus auto-create thresholds |
/options |
View and modify runtime options (max-tokens, max-steps, shell-timeout, token-window) |
/image v0.9.0+ |
Attach an image to the next turn: /image <path> [prompt]
(vision-capable model required)
|
/{routine-id} |
Execute a saved routine (with optional arguments) |
/{specialist-id} |
Execute a saved specialist (with a task description) |
/exit |
Quit Bernard (also: exit, quit, or Ctrl+C) |
/ without triggering a slash command,
escape it with a backslash: \/not-a-command
Escape while the agent is running to interrupt the current turn and
return to the prompt.
5. Tools & Capabilities
Bernard has access to a set of built-in tools that it uses autonomously based on your requests. You don't call tools directly — Bernard decides when to use them.
Shell
Executes shell commands in your current working directory. Output is captured and returned to the AI. Commands have a configurable timeout (default: 30 seconds) and a 10 MB output buffer.
Dangerous Command Detection
Bernard detects potentially dangerous commands and asks for confirmation before executing them. The following patterns trigger the safety check:
rmwith-ror-fflagssudomkfs,dd- Writing to
/dev/sd* chmod 777,chown -Rreboot,shutdownsystemctl stop/disable/maskkill -9,pkill,killall
Memory
Persistent, disk-backed storage at ~/.local/share/bernard/memory/. Survives
across sessions. The agent can list, read, write, and delete memory entries by key.
Use this for things like project conventions, server addresses, or personal preferences.
bernard> remember that this project uses pnpm
▶ memory: write "project-conventions"
Saved to persistent memory.
Scratch
Session-only scratch notes for tracking complex task progress, intermediate findings, and working plans. Scratch notes survive context compression within a session but are discarded when the session ends. Same actions as memory: list, read, write, delete.
Web Read
Fetches a web page by URL and converts it to markdown. Useful for reading documentation, articles, Stack Overflow answers, or any public URL. Supports an optional CSS selector to extract specific content.
- Strips navigation, footer, scripts, and other non-content elements
- HTML limit: 1 MB, output limit: 20,000 characters
- Fetch timeout: 15 seconds
Sub-Agents
Bernard can delegate tasks to independent sub-agents that run in parallel. Each sub-agent gets its own AI context with access to the base tools (shell, memory, web, cron, MCP tools, etc.) but not the agent tool itself (no recursive sub-agents), and no conversation history.
- Up to 4 concurrent sub-agents
-
Each sub-agent gets 50% of the main agent’s step budget (e.g. 13
steps when
max-stepsis 25) - Task descriptions must be self-contained — sub-agents have no prior context
- Sub-agents can access RAG memory and persistent memory for context
bernard> check disk usage and count lines of code in parallel
▶ agent: "Check disk usage"
▶ agent: "Count lines of code"
[sub:1] ▶ shell: df -h /
[sub:2] ▶ shell: find . -name "*.ts" | xargs wc -l
Disk: 42G used of 256G (16%). Code: 2,847 lines across 23 files.
Tasks v0.6.0+
Tasks are isolated, focused executions that return structured JSON output. Unlike
sub-agents (which return free-form text), tasks always produce a
{status, output, details?} response — making them ideal for
machine-readable results, routine chaining, and conditional branching.
-
Single-step budget (
maxSteps: 2— one tool-use round + structured result) — quick and deterministic -
Structured JSON output — always returns
{status: "success"|"error", output, details?} - No conversation history — completely isolated from the current session
-
Available as both a tool (the agent can call
taskduring routines) and a REPL command (/task) - Shares the same 4-slot concurrency pool with sub-agents
bernard> /task List all TypeScript files in src
┌─ task — List all TypeScript files in src
▶ shell: find src -name "*.ts" -type f
└─ task success: Found 23 .ts files
task tool for isolated
sub-steps and use the structured JSON result to decide next steps — enabling
conditional branching and output chaining within routines.
Image Attachment v0.9.0+
Use /image <path> [prompt] in the REPL to attach an image to the next
turn. The image is loaded into the message as a vision content block, so it works only
with vision-capable models (Anthropic Claude, OpenAI GPT-4o family, etc.).
- Supported formats: PNG, JPEG, GIF, WebP — resolved relative to the current working directory
- Optional inline prompt:
/image diagram.png explain the data flow -
Switch to a vision-capable model with
/modelfirst if your current default doesn't support images
Tool Augmentation Layer v0.9.0+
Every tool's execute function is wrapped in a transparent layer that observes
calls, records errors, and patches the system prompt with concrete bad-example fixes the
next turn. The invariant is strict: only real observed failures become bad examples
— no hallucinated guidance.
-
One JSON profile per tool at
tool-profiles/<key>.json, capped at 5 good and 5 bad examples (oldest drops first) -
Shell commands are split by prefix into
shell.git,shell.gh,shell.docker,shell.npm,shell.fs,shell.http— each sub-category gets scoped guidance -
MCP tools are augmented automatically (identified by the
__separator) and stored atmcp.<name>.json -
When a retry succeeds, the bad example's
fixfield is patched with the working args -
Seeded defaults ship for
shell.git,shell.fs,shell.npm,web_read,file_read_lines,file_edit_lines
Date/Time
The datetime tool returns the current date and time information. The
time_range tool calculates the duration between two military/24-hour times,
and the time_range_total tool calculates the total duration across multiple
military time ranges.
Wait
Pauses execution for a specified number of seconds. Useful when a task requires waiting within the current turn (e.g., server restart, build propagation).
- Minimum: 0.1 seconds
- Maximum: 300 seconds (5 minutes)
6. Routines v0.5.0+
Routines are named, persistent multi-step workflows that Bernard can execute on demand. Use them to capture repeatable procedures — deploy scripts, release checklists, onboarding flows, code review steps — as structured instructions that Bernard follows with full tool access.
Creating Routines
There are two ways to create a routine:
Natural language
Ask Bernard to save a routine directly. The agent will use the routine tool
to create it:
bernard> save a routine called "deploy-staging" that builds, pushes the docker image, and updates k8s
▶ routine: create { id: "deploy-staging", name: "Deploy to Staging", ... }
✓ Routine "Deploy to Staging" (/deploy-staging) created.
Guided creation
Use the /create-routine command for a guided, interactive experience. Bernard
will ask about your workflow, clarify ambiguities, and draft a well-structured routine
using prompt-engineering best practices before saving:
bernard> /create-routine
What workflow would you like to save as a routine?
… (interactive Q&A to build the routine)
Task routines
Use /create-task to create a routine whose ID follows a
task- prefix convention. Bernard will generate an ID prefixed with
task-, letting you organize quick, focused procedures under a consistent
/task-{name} namespace:
bernard> /create-task
What task would you like to save?
… (interactive Q&A — Bernard will generate an ID prefixed with task-)
bernard> /task-run-tests
(Bernard follows the saved task procedure)
Invoking Routines
Type /{routine-id} to execute a saved routine. Bernard follows the stored
procedure with full access to all tools:
bernard> /deploy-staging
(Bernard follows the saved deploy steps)
bernard> /deploy-staging to production instead
(Bernard follows the routine with "to production instead" as additional context)
Routine names appear in the live autocomplete hints when you type /.
Managing Routines
The agent has a routine tool for full lifecycle management. You can also use
/routines in the REPL for a quick list.
| Action | How |
|---|---|
| List routines | /routines or ask Bernard to list them |
| View a routine | Ask Bernard: “show the deploy-staging routine” |
| Update a routine | Ask Bernard: “update deploy-staging to add a rollback step” |
| Delete a routine | Ask Bernard: “delete the deploy-staging routine” |
| Create (guided) | /create-routine |
| Create task (guided) | /create-task (auto-prefixes ID with task-) |
Storage: one JSON file per routine in
~/.local/share/bernard/routines/. Maximum 100 routines. IDs must be lowercase
kebab-case (1–60 characters).
7. Specialists v0.6.0+
Specialists are reusable expert profiles — persistent personas with custom system prompts and behavioral guidelines that shape how a sub-agent approaches work. Unlike routines (which define what steps to follow), specialists define how to work.
Creating Specialists
Ask Bernard to create a specialist. The agent will use the specialist tool
with an ID, name, description, system prompt, and optional guidelines:
bernard> create a specialist called "code-reviewer" that reviews code for correctness, style, and security
▶ specialist: create { id: "code-reviewer", name: "Code Reviewer", … }
✓ Specialist "Code Reviewer" (code-reviewer) created.
Each specialist has a system prompt (the persona and behavioral instructions) and optional guidelines (short behavioral rules appended as bullet points).
Invoking Specialists
Type /{specialist-id} followed by a task description to run a specialist.
Bernard delegates the task to a sub-agent that uses the specialist’s system prompt
and guidelines as its persona:
bernard> /code-reviewer review the changes in src/agent.ts
┌─ spec:1 [Code Reviewer] — review the changes in src/agent.ts
▶ shell: git diff src/agent.ts
└─ spec:1 done
Each specialist run gets its own generateText loop with a 10-step budget and
no conversation history. Specialists share the concurrency pool with sub-agents and tasks
(4 slots max).
Auto-Dispatch v0.7.0+
Bernard automatically detects when your message matches a saved specialist’s domain using lightweight keyword matching against specialist names and descriptions. For strong matches (score ≥ 0.8), Bernard delegates to the specialist immediately without asking. For partial matches (score 0.4–0.8), Bernard confirms with you before dispatching. This means you don’t need to remember specialist names — just describe what you need and Bernard will route to the right expert.
Managing Specialists
The agent has a specialist tool for full lifecycle management. You can also
use /specialists in the REPL for a quick list.
| Action | How |
|---|---|
| List specialists | /specialists or ask Bernard to list them |
| View a specialist | Ask Bernard: “show the code-reviewer specialist” |
| Update a specialist | Ask Bernard: “update code-reviewer to also check for accessibility” |
| Delete a specialist | Ask Bernard: “delete the code-reviewer specialist” |
Storage: one JSON file per specialist in
~/.local/share/bernard/specialists/. Maximum 50 specialists. IDs must be
lowercase kebab-case (1–60 characters).
Specialist Suggestions v0.6.0+
Bernard automatically detects recurring delegation patterns in your conversations and
suggests new specialists. Detection runs in the background when you exit a session or use
/clear --save.
When candidates are detected, you’ll see a notification at the start of your next session:
2 specialist suggestion(s) pending. Use /candidates to review.
Use /candidates to see pending suggestions with their name, description,
confidence score, and reasoning. You can then accept or reject candidates conversationally
(e.g., “accept the code-review candidate”), and Bernard will create the
specialist for you.
~/.local/share/bernard/specialist-candidates/.
Overlap Detection v0.8.0+
Before suggesting a new specialist, Bernard computes a token-based similarity score against all existing specialists and pending candidates using weighted Jaccard similarity across four fields: name (30%), description (30%), system prompt (20%), and guidelines (20%).
- Candidates with >60% overlap are suppressed entirely
- Partial overlaps prompt a suggestion to enhance the existing specialist instead of creating a new one
- Prevents specialist bloat by catching near-duplicates before they are saved
Auto-Creation v0.8.0+
Enable automatic specialist creation so high-confidence candidates are saved without
manual review. Configure via the /agent-options command or environment
variables.
bernard> /agent-options auto-create on # Enable auto-creation
bernard> /agent-options auto-create off # Disable auto-creation
bernard> /agent-options threshold 0.85 # Set confidence threshold (0-1)
bernard> /agent-options # Show current settings
Or via environment variables: BERNARD_AUTO_CREATE_SPECIALISTS=true and
BERNARD_AUTO_CREATE_THRESHOLD=0.85.
8. Critic Mode v0.8.0+
Critic mode adds planning, proactive scratch/memory usage, and post-response verification. Toggle it during a session:
bernard> /agent-options # Toggle critic mode (and the other behavior toggles)
When enabled:
- Planning — Bernard writes a plan to scratch before multi-step tasks
- Proactive scratch — Accumulates findings in scratch during complex work
- Verification — After tool-using responses, a critic agent reviews the work and prints a verdict (PASS/WARN/FAIL)
The critic checks that claimed actions match actual tool calls and flags any discrepancies. It adds one extra LLM call after tool-using responses. Simple knowledge answers are not verified.
Enable from /agent-options in the REPL or set
BERNARD_CRITIC_MODE=true
in your environment. Recommended for high-stakes work (deployments, git operations,
multi-file edits).
PAC System (Plan-Act-Critic)
When critic mode is enabled, sub-agents and specialists also get critic verification via a reusable PAC loop. The PAC loop runs the critic after each sub-agent/specialist execution, and if the critic finds issues, it retries the task with feedback (up to 2 retries). This applies to:
- Sub-agents (
agenttool) - Specialist runs (
specialist_runtool) - Cron job executions (daemon mode)
Verdicts
The critic prints a verdict after each verified response:
-
PASS — Displayed as a compact single-line badge (e.g.,
└— critic PASS) - WARN — Also compact single-line; treated as a pass (no retry)
- FAIL — Full multi-line explanation with details about what went wrong
PASS and WARN are kept brief to reduce terminal noise, while FAIL always shows the full explanation so you can understand what needs attention.
9. Context Management v0.8.0+
Bernard automatically manages conversation context to keep within model token limits and provide temporal awareness throughout your sessions.
Auto-Continue on Truncation
If a response hits the max-tokens limit and is cut off, Bernard automatically
continues where it left off — up to 3 continuations. After completing, it shows a
recommended max-tokens value based on actual usage (calculated as 1.25×
the total tokens used).
If the response is still incomplete after 3 continuations, a warning is shown with
instructions to increase the limit via /options max-tokens <value>.
Configurable Loop Limits
Control the maximum number of tool-call iterations per request with the
BERNARD_MAX_STEPS environment variable (default: 25). You can also change it
at runtime with /options max-steps <value>.
- Sub-agents automatically receive 50% of the main agent’s step budget
- When the step limit is hit, Bernard offers to double it for the current session
- Step budget resets at the start of each new request
Timestamp Awareness
Every user message is prefixed with an ISO 8601 timestamp, giving Bernard precise
temporal context throughout multi-turn conversations. The system prompt includes the
current date and time (not just the date), and the time tool output
includes seconds and timezone information.
Diagnostics
Use /options debug in the REPL to print a diagnostic report useful for
troubleshooting. The report includes:
- Runtime info (Bernard version, Node.js version, OS)
- LLM configuration (provider, model, max tokens, max steps)
- API key status (configured/not set — keys are never shown)
- MCP server status
- RAG/memory/cron state
- Conversation stats and active settings
- File paths
No secrets are included in the output.
10. Reference Resolution v0.9.0+
Before each turn Bernard resolves the named entities in your message ("my brother", "the
staging cluster") against persistent memory. Anything that resolves is appended to the
system prompt as a hidden ## Resolved References block, so the agent sees
concrete identifiers without you having to repeat them.
Resolver
A short LLM pass returns one of four outcomes:
-
resolved— the entity matches one memory; Bernard inlines the value -
ambiguous— multiple candidates; Bernard shows an arrow-key menu so you can pick -
unknown— no match; Bernard either tries a tool lookup (see below) or asks for free-form text -
noop— no entities to resolve, or the LLM call failed (fail-open)
Confirmed answers are written to memory/rewriter-hints.md so the same
reference resolves silently next time.
Tool Lookup
When the resolver returns unknown and
BERNARD_REFERENCE_LOOKUP is on (the default), Bernard picks one read-only
allowlisted tool — e.g. contacts__search, web_search,
an MCP *_list / *_read — and runs it with a hard 5-second
timeout enforced via Promise.race against a real timer (resilient to tools
that ignore abortSignal). The result is parsed into one of
none / found / ambiguous; on
found Bernard shows a Save / Edit / Skip menu before persisting to memory.
Every stage fails open — if anything goes wrong, you simply get the original prompt
for the value.
Use BERNARD_LOOKUP_TOOLS=tool_a,tool_b to extend the allowlist. Only allow
tools that are read-only.
Prompt Rewriter
After reference resolution, a second LLM pass rewrites the user's message for the active
model family using the per-model rewriterHint in
src/providers/profiles.ts. Resolved entities can be inlined inline, jargon is
smoothed, and instructions are normalised. Temperature is 0, output falls back to the
original prompt on any error, and the toggle lives at
BERNARD_PROMPT_REWRITER (also flippable from /agent-options).
11. Coordinator (ReAct) Mode v0.9.0+
Coordinator mode turns each turn into a structured
think → act → evaluate → decide loop. Bernard
plans the work with a plan tool, talks itself through the rationale with
think, and re-checks the plan after each step with evaluate.
It's slower per turn but dramatically better at multi-step work that combines tool calls
and reasoning.
-
Toggle with
BERNARD_REACT_MODE=trueor interactively from/agent-options -
Per-turn step budget grows to
min(BERNARD_MAX_STEPS × 3, 150)— sub-agents and specialists are unaffected -
Worst-case step count per turn is
effectiveMaxSteps × 3; the enforcement loop may re-prompt up to 2 extra times if a plan step is still unresolved -
New tools available to the agent:
plan,think,evaluate
12. Cron Jobs v0.5.0+
Bernard can schedule recurring tasks that run in the background on a timer. Cron jobs execute an AI prompt through the agent on each run, with access to all tools.
Creating Jobs
Ask Bernard to create a cron job with natural language, or the agent will use the
cron_create tool with a name, cron expression, and prompt:
bernard> every hour, check if the API is healthy
▶ cron_create: "api-health-check"
Schedule: 0 * * * * (every hour)
✓ Created cron job — runs every hour.
The cron daemon starts automatically when the first job is created.
Managing Jobs
The agent has tools for full cron job lifecycle management:
| Tool | Description |
|---|---|
cron_create |
Create a new scheduled job |
cron_list |
List all jobs with status |
cron_get |
Get full details of a job including prompt and last result |
cron_run |
Manually trigger a job immediately |
cron_update |
Update a job's name, schedule, or prompt |
cron_enable |
Enable a disabled job |
cron_disable |
Disable a job without deleting it |
cron_delete |
Permanently delete a job |
cron_status |
Check daemon status and job counts |
cron_bounce |
Restart the cron daemon |
Daemon Management
The cron daemon is a background process that ticks and executes jobs on schedule. It starts automatically when enabled jobs exist and stops automatically when none remain.
- The daemon runs independently of the REPL — jobs continue after you exit Bernard
- Use
/cronin the REPL to check daemon status -
If the daemon misbehaves, restart it with the
cron_bouncetool orbernard cron-bounce
Alerts & Notifications
Cron jobs can generate alerts (e.g., when a monitored API goes down). Alerts are stored locally and can trigger desktop notifications.
Use the --alert <id> flag to open a Bernard session with alert context
pre-loaded, so you can review and act on the alert immediately.
$ bernard --alert abc123
Alert from cron job: api-health-check
Message: API returned 503
Time: 2025-01-15T10:00:00Z
Logs
Cron job execution logs are stored locally. The agent has the following tools to inspect and manage past runs:
cron_logs_list— List recent execution runs for a specific jobcron_logs_get— Retrieve a specific log entry by ID-
cron_logs_summary— Aggregate statistics across jobs (run counts, success/error rates) -
cron_logs_cleanup— Rotate and delete old log entries to reclaim space
Notes v0.9.0+
Each cron job has a private notebook so long-running schedules don't redo work after
restarts or learn the same lesson twice. The daemon injects a scoped variant of these
tools into every run, bound to the current job.id and runId:
cron_notes_read— Read the latest notes for the current jobcron_notes_write— Append a note to the current job's notebookcron_notes_list— List jobs that have at least one notecron_notes_view— View notes for a specific job by id
Notes live in ~/.local/share/bernard/cron/notes/<job-id>.json, capped
at 100 entries per job with atomic writes. Anything written during a run is appended to
the matching cron_logs_get output as a
## Notes written during this run section, so you can read the run log and the
notes in one place.
CLI Commands
Cron jobs can also be managed from the command line without entering the REPL:
| Command | Description |
|---|---|
bernard cron-list |
List all cron jobs with status |
bernard cron-run <id> |
Manually run a job immediately |
bernard cron-delete <ids...> |
Delete specific jobs by ID |
bernard cron-delete-all |
Delete all cron jobs |
bernard cron-stop [ids...] |
Stop the daemon (no args) or disable specific jobs |
bernard cron-bounce [ids...] |
Restart the daemon (no args) or bounce specific jobs |
13. MCP (Model Context Protocol)
Bernard supports the Model Context Protocol for connecting to external tool servers. MCP servers extend Bernard with additional capabilities like file system access, database queries, API integrations, and more.
Configuration
MCP servers are configured in ~/.config/bernard/mcp.json. The file uses a
mcpServers object where each key is the server name:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"],
"env": {}
},
"remote-api": {
"url": "https://api.example.com/mcp",
"type": "sse",
"headers": {
"Authorization": "Bearer token..."
}
}
}
}
Stdio Servers
Stdio-based MCP servers are spawned as child processes. Specify the
command, optional args array, and optional
env object:
| Field | Required | Description |
|---|---|---|
command |
Yes |
Executable to run (e.g., npx, python, node)
|
args |
No | Array of command arguments |
env |
No | Environment variables to pass (merged with process env) |
URL-Based Servers
URL-based servers connect over HTTP using SSE or HTTP transport:
| Field | Required | Description |
|---|---|---|
url |
Yes | Server URL |
type |
No | Transport type: sse (default) or http |
headers |
No | HTTP headers to send with requests |
You can also add URL-based servers from within a session using the
mcp_add_url tool.
Commands
| Command / Tool | Description |
|---|---|
/mcp |
REPL: Show connected servers and their tools |
bernard mcp-list |
CLI: List configured MCP servers |
bernard remove-mcp <key> |
CLI: Remove a configured MCP server |
mcp_config |
Agent tool: List, add, remove, or inspect MCP servers |
mcp_add_url |
Agent tool: Add a URL-based MCP server |
14. RAG Memory
Bernard automatically builds a long-term knowledge base from your conversations using local embeddings and retrieval-augmented generation (RAG). No data leaves your machine.
How It Works
- Extraction — When a session ends (and the conversation has 4 or more messages), a background worker extracts durable facts from the conversation. Each domain has a specialized extraction prompt that filters for relevant facts.
-
Embedding — Facts are embedded locally using
fastembed
— no API calls required. Embeddings and facts are stored in
~/.local/share/bernard/rag/memories.json. - Retrieval — On each new message, Bernard searches the RAG store using cosine similarity. The top results (up to 3 per domain, 9 total) are injected into the system prompt as recalled context.
- Deduplication — Near-duplicate facts (similarity > 0.92) are automatically skipped to prevent bloat.
Domains v0.3.0+
Facts are categorized into four domains, each with a specialized extraction prompt:
| Domain | Description | Examples |
|---|---|---|
tool-usage |
Tool Usage Patterns | Command sequences, error resolutions, build/deploy workflows, git patterns |
user-preferences |
User Preferences | Communication style, workflow conventions, naming preferences, "always/never" rules |
general |
General Knowledge | Project architecture, environment info, team context, API endpoints, decisions |
conversations |
Conversation Summaries v0.6.0+ | What was discussed, approaches taken, tools/specialists/routines used, outcomes |
Managing Facts
Use the CLI or REPL to browse and manage stored facts:
# List all stored facts
$ bernard facts
# Search facts by query
$ bernard facts "deployment workflow"
# Search using a file's contents as query
$ bernard facts ./src/deploy.ts
# Delete ALL facts (requires exact confirmation phrase)
$ bernard clear-facts
Both commands show facts grouped by domain and offer an interactive prompt to select and
delete facts by number (e.g., 1,3,5-8).
The clear-facts command deletes all stored facts. It displays a
per-domain breakdown and requires you to type the exact phrase
yes, delete all facts before proceeding.
Within the REPL:
-
/rag— Show total count, per-domain breakdown, and 10 most recent facts -
/facts— Show facts currently in the context window with similarity scores
Auto-Expiration v0.4.0+
RAG memories have a configurable TTL (default: 90 days). Facts that are never accessed
decay over time and are eventually pruned. Actively recalled facts have their
lastAccessed timestamp refreshed, keeping them alive.
- Max memories: 5,000
- Default TTL: 90 days
- Decay half-life: 90 days (used for capacity-based pruning when memory count exceeds the cap)
- Similarity threshold: 0.35 (minimum for retrieval)
- Disable RAG entirely by setting
BERNARD_RAG_ENABLED=false
15. Auto-Updates v0.3.0+
Bernard can check for new versions on npm and install them for you. Update checks are cached for 24 hours.
# Check for updates interactively
$ bernard update
# Or from within the REPL
bernard> /update
# Enable automatic update checks on startup
$ bernard auto-update on
# Disable automatic update checks
$ bernard auto-update off
When auto-update is enabled, Bernard checks for new versions each time you start a session and notifies you if one is available.