Metadata-Version: 2.4
Name: fredcode
Version: 0.7.4
Summary: Fred — DeepSeek-powered agentic coding CLI
Author-email: Nolan Whitley <hello@fredcode.net>
License-Expression: LicenseRef-Proprietary
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: diskcache
Requires-Dist: grep-ast
Requires-Dist: httpx>=0.27
Requires-Dist: networkx>=3.2
Requires-Dist: openai>=1.50
Requires-Dist: packaging>=21
Requires-Dist: pathspec
Requires-Dist: prompt-toolkit>=3.0
Requires-Dist: pydantic>=2.7
Requires-Dist: python-frontmatter>=1.1
Requires-Dist: rich>=13.7
Requires-Dist: tiktoken>=0.7
Requires-Dist: tree-sitter
Requires-Dist: tree-sitter-language-pack>=1.6
Requires-Dist: truststore>=0.9
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Provides-Extra: keychain
Requires-Dist: keyring>=24; extra == 'keychain'
Provides-Extra: telemetry
Requires-Dist: psycopg[binary]>=3.2; extra == 'telemetry'
Description-Content-Type: text/markdown

# fred

`fred` is an agentic coding CLI for the terminal. It runs a streaming model
loop over DeepSeek-compatible APIs, dispatches a small set of file/shell/
search tools, gates destructive operations behind permission rules, and
completes multi-step coding tasks autonomously.

The package is `fred` internally (Python imports), the binary is `fred`,
and the PyPI name is `fredcode`. The project was originally `dsc` (from
"DeepSeek-CLI") and renamed to `fred` mid-flight. The only carried-over
fallback is `~/.config/dsc/credentials.json`, which is migrated
transparently to `~/.config/fred/credentials.json` on first run.

For deeper context see [`AGENTS.md`](AGENTS.md) (project conventions
and sharp edges; read it before editing this repo).

## What's new in 0.4.0

- **Server-fetched system + init + subagent prompts.** The wheel now
  ships zero prompt text. The CLI's main system prompt, the `/init`
  subagent prompt + 3 directives, and the `explore`/`plan`/`general`
  subagent profiles all resolve through `fred.prompt_cache` against
  `~/.config/fred/agent-prompts.json`, populated on every successful
  `fred login` from `https://app.fredcode.net/api/cli/agent-prompts`.
- **No bundled fallback.** A fresh install with no cached prompts
  exits cleanly (code 3) with a `Run \`fred login\`` message instead
  of starting up with a stub prompt. Pre-launch baseline; the prompts
  are the product.
- **Rate-card refresh on login** (carried over from 0.3.x). The
  long-deferred login-time fetch from `/api/pricing` is now wired.
  `~/.config/fred/rate-card.json` refreshes on every `fred login`,
  alongside the new agent-prompts cache.
- **Why the bump.** Both changes ship a non-trivial new dependency on
  the FredWeb side (a logged-in API call before the CLI is functional).
  Anyone upgrading from 0.3.x will need to run `fred login` once after
  the upgrade — the next session reads from the freshly populated
  cache.

## What's new in 0.3.0

- **Web research tools.** New `web_search` and `web_fetch` tools that go
  through the FredWeb proxy → Tavily. Permission-gated; both surface a
  cost estimate on the y/n/a/d Panel before approval. Server-side billed
  alongside token costs (basic search ≈ $0.020, advanced ≈ $0.040).
- **Toggle-gated.** Web research is off by default — flip it on at
  `https://app.fredcode.net/settings`. The CLI surfaces a clear "enable
  at <url>" hint when the toggle is off.
- **Telemetry payloads.** Three new event kinds — `web_search`,
  `web_fetch`, and `web_research_chain` — record query length (not
  text), result counts, top domain, depth, billed microcents, and
  search→fetch chain shape. Lets us measure depth ROI, truncation
  cost, and toggle adoption from the same `fred_events` stream.

## What's new in 0.2.0

- `/flash` and `/pro` slash commands — swap the main slot in one keystroke.
  `/pro` confirms once with the cost warning ($3.48/M output vs $0.28/M)
  and remembers the answer. Default stays on `deepseek-v4-flash`.
- Persistent model preferences at `~/.config/fred/preferences.json` —
  your last `/model` choice survives restarts. Env vars still win for CI.
- Rate-card cache + bundled fallback (`src/fred/rates.py`,
  `src/fred/bundled_rates.py`) replaces the hardcoded cost table.
- Update notice on startup: a background poll of PyPI surfaces
  "v0.X.Y available" and `fred update` runs the upgrade.
- Auto-publish CI: bumping `version` in `pyproject.toml` and pushing to
  main publishes to PyPI and tags `vX.Y.Z`.

## Status

Shipped, on PyPI as `fredcode`, exercised by the full test suite. Phases
0-4 of the implementation plan are done:

- streaming agent loop with retry layer that won't replay tool calls
- managed credentials via `fred login` / `fred logout` / `fred whoami`
- repo map (tree-sitter + PageRank), persistent todos, AGENTS.md memory
- plan/act mode, sandbox + approval axes, output styles
- multi-model routing (main/editor/weak), context compaction, checkpoints
- hooks, permission rules, project rules, MCP stdio servers
- subagent dispatch, status line, telemetry (Postgres, opt-in)
- correlation headers (`x-fred-session-id`, `x-fred-turn-id`) so the
  Cloudflare proxy can attribute usage events back to a session

## Install

The shortest path that actually works on a fresh machine — uv ships
its own Python and skips every `pip` / `pyenv` / `pipx` install bug
you've hit before:

```sh
# 1. Install uv (skip if you already have it)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows:  powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# macOS:    brew install uv  (alternate)

# 2. Install fred
uv tool install fredcode
```

After install, `fred` is on your `PATH`. Upgrade with `uv tool upgrade
fredcode` or the built-in `fred update`. If you already have a venv
or pipx and prefer them, `pip install fredcode` and `pipx install
fredcode` work too.

For development, clone and use an editable install in a venv:

```sh
git clone https://github.com/nwhitley-trAIner/fred.git
cd fred
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest
```

Optional extras: `[telemetry]` for the Postgres writer, `[keychain]` for
macOS Keychain credential mirroring.

## Quick start

Authenticate via the browser PKCE flow (opens `https://app.fredcode.net`,
the Vercel-hosted console; use `--device-code` on headless boxes):

```sh
fred login
```

The CLI talks to `https://api.fredcode.net/v1` (Cloudflare Worker proxy
in front of DeepSeek). `fred whoami` confirms the server-authoritative
balance and the key prefix.

REPL:

```sh
fred
```

One-shot:

```sh
fred -p "fix the bug in examples/buggy.py and verify"
```

Plan mode (read-only until `exit_plan_mode`):

```sh
fred --plan
```

Skip permission prompts (still subject to sandbox):

```sh
fred --yolo -p "run the test suite"
```

## CLI flags

| Flag | Description |
|---|---|
| `-p`, `--prompt TEXT` | One-shot mode: run this prompt and exit. |
| `--plan` | Start in plan mode (read-only allowlist + `exit_plan_mode`). |
| `--yolo` | Skip permission prompts. Combine with a sandbox if used. |
| `--no-stream` | Disable rich.Live streaming (use on tmux/Windows Terminal). |
| `--model NAME` | Main-slot model. Default `deepseek-v4-flash`. |
| `--architect` | Architect mode flag (accepted; full editor coupling deferred). |
| `--output-style concise\|explanatory` | Output style for the next session. |
| `--sandbox ro\|workspace-write\|full` | macOS Seatbelt sandbox mode. |
| `--approval untrusted\|on_request\|never` | Permission Panel mode. |
| `--no-confirm-pro` | Skip the first-time `/pro` confirmation prompt. |
| `--version` | Print version and exit. |

Subcommands: `fred login` (PKCE; `--device-code` for headless),
`fred logout` (revoke + delete local credential), `fred whoami` (server-
authoritative balance + key prefix), `fred update` (run `pip install
--upgrade fredcode`; the REPL also prints a one-line "v0.X.Y available"
notice on startup when a newer release is on PyPI).

## Tools

The default registry is built in `fred.tools.registry.default_registry`.

| Tool | Purpose | Permission |
|---|---|---|
| `view` | Read a file (numbered) or list a directory | no |
| `str_replace` | Replace a UNIQUE string in a file | yes |
| `create_file` | Create a new file | yes |
| `bash` | Streaming shell command (cwd-scoped, sandboxed) | yes |
| `bash_bg` | Spawn a backgrounded shell command | yes |
| `bash_read` | Poll new output from a `bash_bg` handle | no |
| `bash_kill` | Terminate a `bash_bg` process tree | yes |
| `glob` | Find files by pattern | no |
| `grep` | Regex content search (uses `rg` if available) | no |
| `todo_write` | Maintain the session todo list | no |
| `agent` | Dispatch a subagent (explore/plan/general) | no |
| `exit_plan_mode` | Switch from plan to act, commits to a plan summary | no |
| `request_rule` | Pull an "available" rule into the active block | no |
| `mcp__<server>__<tool>` | Tool exposed by a connected MCP server | yes |

Bash specifics: `subprocess.Popen` with merged stdout/stderr, daemon drain
thread, ANSI strip, head+tail truncation (25k each), `cwd` validated
against the project root, optional Seatbelt wrapping.

## Slash commands

REPL only. Grouped by purpose:

**Info**

| Command | Purpose |
|---|---|
| `/help` | Show the slash-command list. |
| `/tools` | List registered tools. |
| `/subagents` | List subagent profiles + their tool subsets. |
| `/cost` | Session token + cost summary; appends server balance when logged in. |
| `/last [n]` | Reprint the Nth-most-recent tool result Panel (default 1). |
| `/repomap` | Print the rendered repo map injected this turn (debug). |
| `/rules` | List active + available rules from `.fred/rules/*.md`. |
| `/hooks` | List configured hooks per event. |
| `/perms` | List active permission rules (deny → ask → allow). |
| `/mcp` | List connected MCP servers + their tool counts. |
| `/checkpoints` | List the 20 most-recent shadow-git checkpoints. |
| `/todos` | Show the current todo list. |

**State**

| Command | Purpose |
|---|---|
| `/clear` | Reset the conversation (rebuilds the system prompt). |
| `/save [path]` | Dump the transcript as JSONL. |
| `/init` | Bootstrap an `AGENTS.md` for the current repo. Detects existing `AGENTS.md` (improve mode), `CLAUDE.md` (migrate mode), or neither (fresh mode); shows a draft preview and confirms before writing. |
| `/compact [focus]` | Run a weak-model summary pass over older history. |
| `/restore <sha>` | Restore the workspace to a checkpoint (with confirm). |

**Config**

| Command | Purpose |
|---|---|
| `/yolo` | Toggle permission bypass. |
| `/sandbox` | Print sandbox + approval modes. |
| `/sandbox <mode>` | Set sandbox mode (`ro`/`workspace-write`/`full`). |
| `/sandbox approval <mode>` | Set approval mode (`untrusted`/`on_request`/`never`). |
| `/mode plan\|act\|toggle` | Switch between plan and act mode (Shift+Tab also cycles). |
| `/style concise\|explanatory\|toggle` | Flip output style. Apply with `/clear`. |
| `/model` | Print all three model slots. |
| `/model <name>` | Swap the main slot (back-compat shorthand). |
| `/model <slot> <name>` | Swap a specific slot (`main`/`editor`/`weak`). |
| `/flash` | Collapse all four slots to `deepseek-v4-flash` (default, cheap). |
| `/pro` | Enable architect topology — `main` = pro, `editor`/`weak`/`subagent_main` = flash. First use prompts with the cost disclosure, then remembers. |
| `/think on\|off\|show` | Toggle thinking display, or reprint last turn's reasoning. |
| `/perms add <rule> <list>` | Append a rule to `.fred/settings.local.json`. |
| `/perms remove <rule>` | Remove a rule from any list in the local file. |

**Exit**

| Command | Purpose |
|---|---|
| `/exit` (`/quit`) | Quit the REPL. |

REPL extras: `@path` embeds file content, `!cmd` runs a shell command and
expands its output into the prompt, `Shift+Tab` cycles plan ↔ act.

## Modes: plan and act

`act` (default) gives the model the full registry. `plan` swaps in a
read-only allowlist (`view`, `grep`, `glob`, `repo_map`, `todo_write`,
`exit_plan_mode`); any other tool returns `Error: tool <name> not
available in plan mode. Use ExitPlanMode to continue.` The model
exits plan mode by calling `exit_plan_mode` with a one-line summary,
which flips the mode in place.

## Web research

`web_search` and `web_fetch` give the agent live internet access via
Tavily, routed through the FredWeb proxy at `api.fredcode.net`. Both
require permission (the y/n/a/d Panel shows the estimated cost before
you approve) and respect a 100KB byte cap on returned content.

To enable: visit `https://app.fredcode.net/settings`, flip the **Web
research** toggle, and confirm the disclosure. While off, the model
sees a clear `"web research is disabled. Enable at …"` error and falls
back to its training knowledge.

Pricing (full retail with 2.5× margin):

| Action | Cost |
|---|---|
| `web_search` basic | $0.020 / call |
| `web_search` advanced | $0.040 / call |
| `web_fetch` basic | $0.020 per 5 URLs |
| `web_fetch` advanced | $0.040 per 5 URLs |

Bills against the same credits balance as token usage. Internal accounts
bypass billing while still recording usage for analytics.

## Repo map

A tree-sitter + PageRank repo map is built at session start (cold scan)
and re-rendered per turn. Languages with shipped tag queries: Python,
JavaScript, TypeScript, TSX, Go, Rust. Files in `chat_files`,
`viewed_files`, and `mentioned_idents` (parsed from the latest user
input) personalize the rank vector. Disable with `FRED_REPOMAP=0`.
Inspect with `/repomap`.

## Persistent todos

A todo list is injected as a synthetic system message AFTER the cacheable
prefix on every iteration so the model can read and update it. Set
`FRED_AUTO_SEED_TODOS=1` to print a one-shot nudge when the user's first
prompt looks multi-step (>3 sentences, "first…then", "step N", or `1.`
list). Inspect with `/todos`.

## Hooks

Four lifecycle events: `PreToolUse`, `PostToolUse`, `UserPromptSubmit`,
`Stop`. Configure in `~/.fred/settings.json` (user) and/or
`.fred/settings.json` (project, walked from cwd to git root or `$HOME`):

```json
{
  "hooks": {
    "PreToolUse": [
      {"matcher": "Bash(rm -rf *)", "command": "echo blocked", "timeout": 5}
    ]
  }
}
```

Exit-code semantics: `0` allow (PreToolUse may emit
`{"updatedInput": {...}}` JSON on stdout to mutate args), `2` block
(structured error surfaced), other non-zero warn-only. Inspect with
`/hooks`.

## Permission rules

Three lists — `allow`, `ask`, `deny` — of `Tool(specifier)` patterns,
evaluated deny → ask → allow before the y/n/a/d Panel. Configure in
`.fred/settings.json` (project, shared) or `.fred/settings.local.json`
(local, gitignored — picking `[a]` at the Panel writes here):

```json
{
  "permissions": {
    "deny":  ["Bash(rm -rf *)"],
    "ask":   ["Bash(git push *)"],
    "allow": ["Bash(git status *)", "view", "grep"]
  }
}
```

`Bash(...)` allow-rules refuse to authorize commands containing shell
chaining metacharacters (`;`, `&&`, `||`, `|`, `&`, backticks, `$()`,
newlines) — these fall through to the Panel. Deny-rules still match.
Manage rules with `/perms`, `/perms add`, `/perms remove`.

## Rules: `.fred/rules/*.md`

Cursor-style conditional rule injection. Rule files have YAML
frontmatter:

```markdown
---
name: api-conventions
description: HTTP handler conventions (run when editing src/api/**)
alwaysApply: false
globs: ["src/api/**/*.py"]
---
- Always validate inputs with pydantic.
- Return typed dataclasses, not dicts.
```

Selection per turn: `alwaysApply: true` (always), `globs` (matched
against `chat_files` via pathspec), or explicitly requested via
`request_rule(name)`. Description-only rules are listed under
"available" so the model knows they exist. Project rules
(`<cwd>/.fred/rules/`) win on name collision over user rules
(`~/.fred/rules/`). Disable with `FRED_RULES=0`.

## Multi-model routing

Four slots — `main` (reasoning, every turn), `editor` (file-edit
review/repair pass via `fred.editor_pass`), `weak` (compaction), and
`subagent_main` (the `agent` tool's child sessions). All four default
to `deepseek-v4-flash`. Inspect/swap with `/model`, or use the `/flash`
and `/pro` shortcuts.

`/pro` enables architect topology: `main = deepseek-v4-pro`, with
`editor`, `weak`, and `subagent_main` all on `deepseek-v4-flash`. Pro
reasons; flash repairs file-edit args, runs compaction, and powers
subagents. `/flash` collapses every slot back to flash. The first time
you run `/pro` it prompts with the architect cost disclosure (~one
extra flash call per file-edit tool_call) and sets a persistent
`warned_about_architect` flag. Opt out of the prompt entirely with
`FRED_NO_CONFIRM_PRO=1` or `fred --no-confirm-pro`.

Slot-resolution order (top wins):

1. CLI flags (`--model`)
2. Env vars (`FRED_MAIN_MODEL` / `FRED_EDITOR_MODEL` / `FRED_WEAK_MODEL`
   / `FRED_SUBAGENT_MAIN_MODEL`). Env wins over the file so CI
   stays predictable.
3. `~/.config/fred/preferences.json` (written by `/model`, `/flash`,
   `/pro`)
4. The package default (`deepseek-v4-flash`)

The preferences file (`mode 0644`, separate from credentials) holds
`main_model`, `editor_model`, `weak_model`, `subagent_main_model`,
`warned_about_architect`, the legacy `warned_about_pro`, and an
auto-inferred `preset` label (`flash` / `architect` / `premium` / `null`).
See `src/fred/preferences.py`.

## Status line and output styles

`/style explanatory` adds one operating-principles bullet asking the
model for a short paragraph of reasoning per significant change. The
fragment is inserted before the `# Safety` block; flip back with
`/style concise`. Applying mid-session takes effect after `/clear` (the
system prompt rebuilds).

The end-of-turn status line summarizes model · mode · tokens (with
cache-hit %) · cost · repo files · todos. `FRED_REDUCED_MOTION=1`
swaps the horizontal rule for a plain dim print.

## Sandbox: macOS Seatbelt

Two orthogonal axes: `sandbox_mode` (kernel-enforced ground truth) and
`approval_mode` (the y/n/a/d Panel gate).

| Mode | Effect |
|---|---|
| `sandbox=ro` | Reads anywhere, no writes, no network. |
| `sandbox=workspace-write` (default) | Writes inside project root + `/tmp` + `$TMPDIR`; reads anywhere; no network. |
| `sandbox=full` | File ops anywhere; network still denied. |
| `approval=untrusted` | Show Panel for ALL permission-required tools. |
| `approval=on_request` (default) | Show Panel only when no rule grants. |
| `approval=never` | Skip the Panel entirely. Sandbox is the defense. |

macOS-only in v1; on Linux the wrapper is a no-op (un-sandboxed bash
runs unchanged). Set with `--sandbox` / `--approval`, env, or
`.fred/settings.json` `{"sandbox": {"mode": "..."}}`.

## MCP servers

Stdio-transport Model Context Protocol servers are spawned at session
start and their tools are merged into the registry as
`mcp__<server>__<tool>`. Configure in `.fred/settings.json`:

```json
{
  "mcp": [
    {
      "name": "github",
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/github-mcp.js"],
      "env": {"GITHUB_TOKEN": "$GITHUB_TOKEN"},
      "init_timeout": 10
    }
  ]
}
```

`$VAR` substitution in `env` references the parent environment.
Schemas are deferred by default (a stub description ships in the
prefix; the full JSON schema is fetched on first invocation). Force
eager loading with `FRED_MCP_SCHEMAS=eager` or
`ENABLE_TOOL_SEARCH=false`. Inspect with `/mcp`.

## Compaction

Two stages on top of the token-budget tracker:

1. `prune_messages` — runs before every model call. Elides verbose tool
   results (>20k chars) older than the last 20k-token window with a
   short `[elided: <tool> on <args>, <N> chars]` marker.
2. `compact_messages` — fires when the budget tracker hits ≥85% of
   context. Splits history into older + recent halves, runs the older
   half through the weak model, replaces it with one synthetic system
   message tagged `# Compacted history`. Manual trigger: `/compact
   [focus hint]`.

Both preserve the system prompt at index 0 so the cache prefix still
hits.

## Checkpoints

After each successful write-flavored tool call, the workspace is
snapshotted into a shadow git repo at
`~/.fred/checkpoints/<workspace_hash>.git` — your project never gains a
`.git`, never sees the shadow author, never has commits appended. List
with `/checkpoints`; restore with `/restore <sha>` (requires explicit
`y/N` confirmation; overwrites files on disk). Stale shadow repos are
pruned weekly. Disable with `FRED_CHECKPOINTS=0`.

## Telemetry

Off by default. Set `FRED_TELEMETRY_DB_URL` to a Postgres connection
string and install the `[telemetry]` extra to enable. The writer runs
on a daemon thread; agent-loop calls into the tracer are non-blocking.

Tables (DDL idempotent; see `src/fred/telemetry/schema.sql`):

- `fred_sessions` — one row per CLI invocation, including
  `parent_session_id` for subagents and a `config_snapshot` JSONB.
- `fred_turns` — one row per model iteration (tokens, finish reason,
  duration, mode).
- `fred_tool_calls` — one row per tool dispatch (outcome, permission
  outcome, duration, matched rule).
- `fred_events` — JSONB event log (api_retry, slash_command, hook_run,
  mcp_*, repo_map_*, checkpoint_*, sandbox_invoked, etc.).

Set `FRED_TELEMETRY_NO_TEXT=1` to skip storing user input / assistant
text. `FRED_TELEMETRY_DEBUG=1` surfaces writer errors.

## Project memory

If `AGENTS.md` exists in the cwd, its contents are appended to the
system prompt under `# Project context`. If both `AGENTS.md` and
`CLAUDE.md` exist, `AGENTS.md` wins.

## Configuration

### Credentials and preferences

`fred login` walks the PKCE flow against `https://app.fredcode.net` and
stores credentials at `~/.config/fred/credentials.json` (mode 0600).
On macOS the api_key is mirrored to Keychain when the `[keychain]`
extra is installed. Legacy credentials at `~/.config/fred/` migrate
transparently on next read.

Non-secret preferences live separately at
`~/.config/fred/preferences.json` (mode 0644): persisted `main_model` /
`editor_model` / `weak_model`, the `warned_about_architect` flag, and a
reserved `preset`. Rate cards used for cost previews cache at
`~/.config/fred/rate-card.json` (with a frozen-at-build fallback in
`src/fred/bundled_rates.py`).

API-key resolution order:

1. `FRED_API_KEY` env var (explicit override; CI use).
2. Stored credentials from `fred login`.
3. `DEEPSEEK_API_KEY` env var (legacy direct-to-DeepSeek path; prints
   a deprecation notice on first use).

Base URL resolution: `FRED_BASE_URL` env > stored credential
`base_url` > `https://api.fredcode.net/v1` (or
`https://api.deepseek.com/v1` for the legacy `DEEPSEEK_API_KEY`-only
path).

### Environment variables

| Variable | Purpose |
|---|---|
| `FRED_API_KEY` | Override API key (CI). |
| `DEEPSEEK_API_KEY` | Legacy direct-to-DeepSeek key (deprecation warning). |
| `FRED_BASE_URL` | Override the chat-completions base URL. |
| `FRED_AUTH_URL` | Override the auth/login server (`https://app.fredcode.net`). |
| `FRED_MAIN_MODEL` | Default model for the main slot. |
| `FRED_EDITOR_MODEL` | Editor-slot model. Inherits main if unset. |
| `FRED_WEAK_MODEL` | Weak-slot model. Inherits main if unset. |
| `FRED_SANDBOX_MODE` | `ro` / `workspace-write` / `full`. |
| `FRED_APPROVAL_MODE` | `untrusted` / `on_request` / `never`. |
| `FRED_NO_BANNER` | Suppress the wolf logo banner. |
| `FRED_NO_CONFIRM_PRO` | `1` skips the first-time `/pro` confirmation. |
| `FRED_NO_UPDATE_CHECK` | `1` skips the once-per-day PyPI version check at startup. |
| `FRED_REDUCED_MOTION` | `1` swaps animated rules for plain dim prints. |
| `FRED_MCP_SCHEMAS` | `eager` to ship full MCP schemas in the prefix. |
| `FRED_MCP_CALL_TIMEOUT` | Override per-call MCP RPC timeout (seconds). |
| `ENABLE_TOOL_SEARCH` | `false` flips MCP schemas to eager. |
| `FRED_REPOMAP` | `0` disables the repo map. |
| `FRED_RULES` | `0` disables `.fred/rules/*.md` injection. |
| `FRED_CHECKPOINTS` | `0` disables shadow-git checkpoints. |
| `FRED_AUTO_SEED_TODOS` | `1` enables the multi-step todo nudge. |
| `FRED_SHOW_SUBAGENTS` | `1` forwards subagent transcripts to the parent console. |
| `FRED_API_RETRIES` | Streaming retry budget (default 3). |
| `FRED_API_BACKOFF_BASE_MS` | Exponential backoff base in ms (default 500). |
| `FRED_TELEMETRY_DB_URL` | Postgres DSN to enable telemetry. |
| `FRED_TELEMETRY_NO_TEXT` | `1` skips storing user input / assistant text. |
| `FRED_TELEMETRY_DEBUG` | `1` surfaces writer errors. |
| `NO_COLOR` | Standard suppression of ANSI colors. |
| `SSL_CERT_FILE` / `REQUESTS_CA_BUNDLE` | Override the PEM trust bundle. |

## Corporate proxy / TLS-intercepting networks

`fred` calls `truststore.inject_into_ssl()` at import, delegating
certificate verification to the OS trust store (macOS Keychain,
Windows Certificate Store, Linux system bundle). If your proxy CA is
already in the OS keychain, `fred` trusts it automatically.

Override with `SSL_CERT_FILE` or `REQUESTS_CA_BUNDLE` if needed.

## Layout

```
src/fred/
  cli.py             # Typer entrypoint, slash commands, banner
  agent.py           # run_turn wrapper around session.run_session
  session.py         # streaming turn loop, hooks dispatch
  client.py          # DSClient + retry layer + cache segments
  permissions.py     # y/n/a/d Panel + RuleEngine + ApprovalMode
  system_prompt.py   # act/plan templates + output-style fragment
  render.py          # rich.Live renderer, status line, subagent card
  context.py         # token budget, prune_messages, compact_messages
  cache_segments.py  # CacheableRequest (DeepSeek/Anthropic shapes)
  config.py          # API-key/base-URL resolution, ModelConfig
  preferences.py     # ~/.config/fred/preferences.json (slots, warned_about_architect)
  rates.py           # rate-card cache + active-card resolution
  bundled_rates.py   # frozen-at-build rate-card fallback (offline first run)
  auth.py            # PKCE login flow, credential persistence
  hooks.py           # PreToolUse/PostToolUse/UserPromptSubmit/Stop
  rules.py           # .fred/rules/*.md loader + applicable_for
  mode.py            # plan/act ContextVar + PLAN_TOOLS allowlist
  todo_inject.py     # persistent todo block injection
  checkpoints.py     # shadow-git workspace snapshots
  repomap/           # tree-sitter walker, parser, graph, render, cache
  mcp/               # stdio MCP client, lifecycle, registry adapter
  telemetry/         # tracer, writer, redact, schema.sql
  tools/             # one file per tool + _sandbox + registry
```

