Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Fabric Administrator & Developer Guide

Generated June 2026 from danielmiessler/Fabric at 29b32f9

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the people who run, deploy, secure, integrate, and extend Fabric: administrators standing up the REST API, DevOps engineers packaging it, security reviewers auditing it, and developers contributing to or building on the code base. It documents Fabric's architecture, configuration surface, security posture, operational procedures, and internals in enough depth to operate it confidently or reconstruct how it works.

For end-user installation and CLI usage, see the companion User Guide. This document assumes that baseline and goes deeper.


1. Executive Summary

Fabric is an open-source Go framework that turns AI prompts into reusable, version-controlled Patterns and applies them to arbitrary input through any of ~30 AI providers. It is delivered as a set of standalone binaries plus a SvelteKit web application.

Aspect Detail
Language Go (single-module repo, github.com/danielmiessler/fabric)
Primary binary cmd/fabric — the CLI and REST/Ollama server
Helper binaries cmd/to_pdf, cmd/code2context, cmd/generate_changelog
Web app web/ — SvelteKit 5 + Tailwind/Skeleton UI
CLI parser jessevdk/go-flags (struct-tag flags)
REST framework gin-gonic/gin with Swagger (swaggo)
Persistence Filesystem under ~/.config/fabric/ (patterns, sessions, contexts, .env); SQLite only in generate_changelog
State model No database server; patterns/sessions/contexts are files
AI providers OpenAI, Anthropic, Gemini, Ollama, Azure (OpenAI/Entra/Gateway), Bedrock, Vertex AI, LM Studio, Perplexity, Codex, Copilot, DigitalOcean, Exolab, plus many OpenAI-compatible vendors
Auth (server) Optional shared API key via X-API-Key header
License MIT

Architectural thesis: Fabric is a thin, well-factored orchestration layer. A CLI front end parses flags, a PluginRegistry wires together vendors and tools, a Chatter assembles a system prompt (strategy + context + pattern + input) and streams it to a vendor, and a filesystem-backed DB stores reusable artifacts. The same core powers a REST API and an Ollama-compatible shim.

         ┌──────────── cmd/fabric (CLI) ────────────┐
         │  internal/cli: flags + command handlers   │
         └───────────────────┬───────────────────────┘
                             │
                ┌────────────▼─────────────┐
                │  internal/core            │
                │  PluginRegistry + Chatter │
                └───┬───────────┬───────────┘
         ┌──────────┘           └───────────┐
 ┌───────▼────────┐               ┌─────────▼─────────┐
 │ plugins/ai/*   │               │ plugins/db/fsdb   │
 │ (vendor clients)│              │ patterns/sessions │
 └────────────────┘               │ contexts / .env   │
 ┌────────────────┐               └───────────────────┘
 │ plugins/template│  ← variables, plugins, extensions
 └────────────────┘
         ▲
         │ same core
 ┌───────┴────────────────┐
 │ internal/server (gin)  │  ← REST API + Ollama shim + Swagger
 └────────────────────────┘

2. Architecture

2.1 Request lifecycle (CLI)

The entry point cmd/fabric/main.go calls cli.Cli(version). That function (internal/cli/cli.go) runs a fixed pipeline:

  1. Init() parses flags (internal/cli/flags.go), then merges YAML config for any flag with a yaml: tag (CLI wins), and reads stdin if piped.
  2. i18n init with the requested/detected language.
  3. initializeFabric() opens the filesystem DB at ~/.config/fabric and builds the PluginRegistry.
  4. A chain of handlers runs, each returning (handled, error) and short-circuiting if it handled the request:
    • handleSetupAndServerCommands — --setup, --serve, --serveOllama
    • handleConfigurationCommands — --updatepatterns, --changeDefaultModel
    • handleListingCommands — --listpatterns/-models/-contexts/-sessions/-strategies/-vendors, voices, transcription models
    • handleManagementCommands — --wipecontext/-session, --printcontext/-session
    • handleExtensionCommands — --listextensions/--addextension/--rmextension
    • tool processing (--youtube, --scrape_url/-question, --spotify), transcription, HTML readability
  5. If none short-circuit, handleChatProcessing builds a ChatRequest/ChatOptions, obtains a Chatter, and streams the response.

2.2 The PluginRegistry (internal/core/plugin_registry.go)

PluginRegistry is the composition root. On construction it instantiates every vendor client and every tool, then configures them from the environment.

type PluginRegistry struct {
    Db                 *fsdb.Db
    VendorManager      *ai.VendorsManager   // configured (usable) vendors
    VendorsAll         *ai.VendorsManager   // every known vendor
    Defaults           *tools.Defaults      // default vendor/model/context-length
    PatternsLoader     *tools.PatternsLoader
    CustomPatterns     *custom_patterns.CustomPatterns
    YouTube            *youtube.YouTube
    Language           *lang.Language
    Jina               *jina.Client
    Spotify            *spotify.Spotify
    TemplateExtensions *template.ExtensionManager
    Strategies         *strategy.StrategiesManager
}
  • VendorsAll holds all registered vendors (sorted case-insensitively by name). VendorManager holds only those that successfully Configure() (i.e., have valid env settings). ConfigureVendors() rebuilds VendorManager from VendorsAll.
  • GetChatter(model, ctxLen, vendor, stream, dryRun) resolves which vendor serves a model: case-insensitive model normalization, vendor/model prefix parsing (e.g. ollama/llama3), ambiguity warnings when multiple vendors offer a model, and a Codex pass-through for subscription-hidden models. If dryRun, it swaps in the dryrun client.
  • SaveEnvFile() serializes every plugin's settings back into ~/.config/fabric/.env.

Vendors registered (see NewPluginRegistry): OpenAI, DigitalOcean, Ollama, Azure, Azure AI Gateway, Azure Entra, Gemini, Anthropic, Vertex AI, LM Studio, Exolab, Perplexity, Codex, Copilot (M365), Bedrock — plus all entries in openai_compatible.ProviderMap.

2.3 The Chatter (internal/core/chatter.go)

Chatter.Send() is where a request becomes a model call.

  1. BuildSession() assembles the conversation. The system prompt is built by joinPromptSections(strategy, context, pattern) — strategy first, then context, then pattern — and the user input is appended (or merged, in --raw mode).
  2. Pattern variables are resolved via template.ApplyTemplate when InputHasVars is set; the pattern itself is loaded with variables applied unless NoVariableReplacement.
  3. Language enforcement: if a non-English language is requested, an instruction to translate the response is wrapped around the system prompt.
  4. The vendor is called via Send() (blocking) or SendStream() (streaming through a channel). Streaming aggregates content, surfaces usage metadata when --show-metadata is set, and records the first stream error.
  5. --suppress-think strips <think>…</think> blocks (configurable tags) after generation.
  6. Special case: when the pattern is create_coding_feature, the response is parsed for a file-changes block and applied to disk (domain.ParseFileChanges / ApplyFileChanges).
  7. If a session name was given, the turn is persisted.

Note

Chatter normalizes the model name to the vendor's canonical casing before sending, and forces Raw = true when the vendor reports NeedsRawMode(model) (e.g. certain Perplexity/Ollama/OpenAI models).

2.4 Domain model (internal/domain)

Type Role
ChatRequest Pattern/context/session/strategy names, variables, message, language
ChatOptions Model + all generation params (temperature, top-p, penalties, seed, thinking, image/audio, search, notification)
Attachment File/URL/bytes attachment with mimetype detection and base64 encoding
StreamUpdate / UsageMetadata Unified streaming payload + normalized token counts
ThinkingLevel off/low/medium/high with token budgets (1024/2048/4096)
FileChange create/update operation for create_coding_feature

Default generation values are pinned as constants (DefaultTemperature=0.7, DefaultTopP=0.9, penalties 0.0) and must match the CLI flag defaults.

2.5 The plugin/settings framework (internal/plugins)

Every vendor and tool implements the Plugin interface:

type Plugin interface {
    GetName() string
    GetSetupDescription() string
    IsConfigured() bool
    Configure() error
    Setup() error
    SetupFillEnvFileContent(*bytes.Buffer)
}

PluginBase provides the machinery: Settings map to environment variables built from the plugin name (BuildEnvVariablePrefix uppercases the name and replaces spaces/hyphens with _, e.g. LM Studio → LM_STUDIO_). Configure() reads env vars into settings and validates required ones; Setup() interactively asks questions; SetupFillEnvFileContent() serializes back to .env. Booleans accept 1/true/yes/on and 0/false/no/off.

2.6 Filesystem database (internal/plugins/db/fsdb)

There is no database server. The "DB" is the directory tree under ~/.config/fabric/:

Entity Storage
Patterns patterns/<name>/system.md (+ custom patterns directory)
Contexts contexts/<name> (plain text)
Sessions sessions/<name> (serialized chat history)
Config .env (keys + defaults), config.yaml (optional)
Strategies strategies/<name>.json
Extensions extensions/extensions.yaml (registry)

Custom patterns live in a separate directory (env CUSTOM_PATTERNS_DIRECTORY) and take precedence over built-ins, so --updatepatterns never clobbers them.

2.7 The template engine (internal/plugins/template)

ApplyTemplate(content, variables, input) resolves {{…}} tokens iteratively until none remain (detecting stuck/unresolvable templates). Token kinds:

  • {{input}} — the user input (internally protected by __FABRIC_INPUT_SENTINEL_TOKEN__).
  • {{variable}} — looked up in the variables map (errors if missing).
  • {{plugin:NS:OP:VAL}} — built-in plugins: text (upper/lower/title/trim), datetime, file (read/tail/exists/size/modified), fetch (get), sys (hostname/user/os/arch/env/pwd/home).
  • {{ext:NAME:OP:VAL}} — registered external extension.

Each built-in plugin enforces guardrails: file blocks .. traversal and caps reads at 1 MB; fetch caps at 1 MB and only accepts text-like content types; sys exposes only whitelisted operations.

2.8 Extensions subsystem (internal/plugins/template)

Extensions run external programs from inside patterns. The registry records a SHA-256 hash of both the YAML config and the executable; before execution, the executor re-hashes and refuses to run if either changed (tamper detection). An extension declares operations with cmd_templates and an output method (stdout or file, with optional path_from_stdout, work_dir, cleanup, and a per-extension timeout). Pipe-separated values become numbered template variables ({{1}}, {{2}}).

2.9 REST API server (internal/server)

Serve(registry, address, apiKey) builds a Gin engine (gin.New() + Logger + Recovery), optionally adds APIKeyMiddleware, mounts Swagger, and registers handlers. ServeOllama additionally mounts Ollama-compatible routes. Storage entities (patterns/contexts/sessions) share a generic StorageHandler[T] exposing CRUD routes.

2.10 Web application (web/)

A SvelteKit 5 SPA (Tailwind + Skeleton UI, Vite 8) that talks to the REST API. Notable build wiring: a prebuild/predev step copies scripts/pattern_descriptions/pattern_descriptions.json into static/data/. The base API URL is read from FABRIC_BASE_URL (web/src/lib/config/environment.ts).

2.11 Internationalization (internal/i18n)

All user-facing strings flow through i18n.T(key). Locale files live in internal/i18n/locales/ for ~10 languages. Language is detected from --language/-g, then LC_ALL/LC_MESSAGES/LANG.


3. System Requirements

Component Requirement
OS Linux, macOS, Windows (amd64 and arm64 binaries published)
Runtime None for prebuilt binaries (statically linked Go)
Build toolchain Go (recent toolchain per go.mod) for go install/from-source
Web app build Node.js ≥ 20, a package manager (pnpm/npm), for web/
Optional: PDF pdflatex (TeX Live/MiKTeX) for to_pdf
Optional: media yt-dlp and ffmpeg for YouTube visual extraction and media splitting
Optional: Swagger regen swag CLI to regenerate docs/swagger.yaml
Network Outbound HTTPS to your chosen AI provider(s); none if using purely local Ollama/LM Studio
Disk Minimal; patterns + sessions are small text files

Note

SQLite (mattn/go-sqlite3, which uses cgo) is only a dependency of the generate_changelog helper, not the core CLI or server.


4. Configuration Mastery

4.1 Configuration precedence

For any flag carrying a yaml: tag, effective value = CLI flag > YAML config > built-in default. Environment variables drive plugin/provider configuration (API keys, URLs) and a few behaviors (per-pattern model, custom patterns directory). The .env file is loaded into the process environment.

4.2 .env — provider keys and defaults

Stored at ~/.config/fabric/.env, written by setup and SaveEnvFile(). Provider variables follow the <VENDOR>_<SETTING> convention. Common keys:

Variable Used for
OPENAI_API_KEY OpenAI
ANTHROPIC_API_KEY Anthropic (Claude)
GEMINI_API_KEY Google Gemini
GROQ_API_KEY Groq
MISTRAL_API_KEY Mistral
OPENROUTER_API_KEY OpenRouter
SILICON_API_KEY SiliconCloud
DEEPSEEK_API_KEY DeepSeek
GROKAI_API_KEY GrokAI
OLLAMA_URL Ollama base URL
LM_STUDIO_API_BASE_URL LM Studio base URL
CUSTOM_PATTERNS_DIRECTORY Path to private custom patterns (supports ~/)
DEFAULT_VENDOR / DEFAULT_MODEL / DEFAULT_MODEL_CONTEXT_LENGTH Default selection
FABRIC_MODEL_<PATTERN> Per-pattern model override, value `vendor
FABRIC_ALIAS_PREFIX Prefix for generated pattern aliases (shell)
GITHUB_TOKEN Used by generate_changelog

Important

The .env file contains secrets. Restrict its permissions (the parent dir is created 0755, the file 0644 by default — tighten to 0600 on shared hosts) and never commit it.

4.3 config.yaml — declarative defaults

Located at ~/.config/fabric/config.yaml (or --config <path>). Only flags with a yaml: tag are honored. Example (internal/cli/example.yaml):

pattern: ai
model: phi3:latest
modelContextLength: 2048
frequencypenalty: 0.5
presencepenalty: 0.5
topp: 0.67
temperature: 0.88
seed: 42
stream: true
raw: false
suppressThink: false
thinkStartTag: "<think>"
thinkEndTag: "</think>"
disableResponsesAPI: true   # for llama-server / OpenAI-compatible local servers

YAML-eligible flags include: pattern, model, vendor, modelContextLength, temperature, topp, presencepenalty, frequencypenalty, stream, raw, seed, suppressThink, thinkStartTag, thinkEndTag, disableResponsesAPI, transcribeFile, transcribeModel, splitMediaFile, voice, notification, notificationCommand, thinking, ytDlpArgs.

4.4 Per-pattern model mapping

FABRIC_MODEL_<PATTERN_NAME>=vendor|model (uppercase, hyphens → underscores) pins a model to a pattern when -m is not passed. Resolved in handleChatProcessing.

export FABRIC_MODEL_SUMMARIZE="Anthropic|claude-opus-4-5"
export FABRIC_MODEL_ANALYZE_CODE="OpenAI|gpt-4o"

4.5 Strategies as config

Strategies are JSON files ({"description": "...", "prompt": "..."}) in ~/.config/fabric/strategies/. The bundled set (data/strategies/): aot, cod, cot, ltm, reflexion, self-consistent, self-refine, standard, tot. Add your own by dropping a JSON file in the directory; the --strategy flag and the /strategies endpoint pick it up.


5. Security

Fabric's threat surface spans local file/command execution (template plugins, extensions, create_coding_feature), the REST server, and secret handling. The code base contains deliberate hardening; administrators should understand and, where applicable, augment it.

5.1 REST API authentication

APIKeyMiddleware (internal/server/auth.go) requires the X-API-Key header to match the --api-key value, returning 401 Missing API Key / 401 Wrong API Key. Swagger paths (/swagger/*) are intentionally exempt so docs are browsable.

Caution

If --api-key is empty, the server logs Starting REST API server without API key authentication and serves all routes unauthenticated. Never expose an unauthenticated server beyond localhost. Always run behind TLS (a reverse proxy) and set a strong key in production.

5.2 Secret masking

GET /config masks API keys to their last 4 characters (maskAPIKey, CWE-200) and returns URLs in the clear. POST /config/update ignores values that still contain * (a redacted placeholder) so a round-trip through the UI never corrupts a stored key.

5.3 File and fetch guardrails (template plugins)

  • file plugin: rejects paths containing .., expands ~/ safely, caps reads at 1 MB.
  • fetch plugin: 1 MB cap, UTF-8 + null-byte validation, only text-like content types; documented as making outbound requests — consider an allowlist in hardened deployments.
  • sys plugin: only whitelisted operations; env reads arbitrary environment variables, so avoid putting secrets in patterns' reach.

5.4 Extension integrity

The extension registry stores SHA-256 hashes of the config and the executable. GetExtension/Verify re-hash before use and refuse to run on mismatch, detecting post-registration tampering. Extensions execute via sh -c, honor a per-extension timeout, and can clean up file output.

Warning

Extensions are arbitrary local command execution by design. Treat registering an extension as granting code-execution trust. Review the executable and cmd_template. Do not register extensions from untrusted pattern bundles.

5.5 create_coding_feature file writes

When this pattern runs, model output is parsed for a file-changes block and written to disk. domain.ParseFileChanges validates: operation must be create/update, path must be non-empty, paths containing .. are rejected (traversal guard), and content > 10 MB is rejected. Still, run it only inside a git repo and review git diff.

5.6 Notification command injection hardening

Custom notification commands receive the title and message as positional shell arguments (sh -c '<cmd> "$1" "$2"' -- title message), not via string interpolation — preventing backtick/$()/;/quote injection (covered by TestSendNotification_SecurityEscaping).

5.7 Network and CORS

The streaming chat handler sets Access-Control-Allow-Origin: http://localhost:5173 (the dev web app origin) and HSTS on error responses. Adjust CORS for your deployment if the web app is served elsewhere; place the API behind a reverse proxy that terminates TLS and sets appropriate headers.

5.8 Secret hygiene checklist

  • [ ] .env permissions tightened (chmod 600) on shared hosts
  • [ ] Server started with a strong --api-key
  • [ ] API reachable only via TLS reverse proxy, not directly on 0.0.0.0:8080
  • [ ] Extensions reviewed and limited to trusted executables
  • [ ] create_coding_feature used only in disposable/reviewed working trees
  • [ ] No secrets embedded in patterns (the sys:env plugin can read them)

6. Deployment & Operations

6.1 Running the REST API

# Local, key-protected
fabric --serve --api-key "$FABRIC_API_KEY" --address ":8080"

# Ollama-compatible shim (adds /api/tags, /api/chat, /api/version)
fabric --serve --serveOllama --api-key "$FABRIC_API_KEY"

Bind to localhost and front it with a reverse proxy for TLS:

server {
    listen 443 ssl;
    server_name fabric.example.com;
    # ssl_certificate / ssl_certificate_key ...
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header X-API-Key $http_x_api_key;
        proxy_buffering off;            # required for SSE streaming
        proxy_set_header Connection '';
        proxy_http_version 1.1;
    }
}

Important

The /chat endpoint streams Server-Sent Events. Disable proxy buffering (proxy_buffering off, and Fabric already sets X-Accel-Buffering: no) or clients will see responses only after completion.

6.2 Containerized deployment

docker run -d --restart unless-stopped \
  -p 127.0.0.1:8080:8080 \
  -v $HOME/.fabric-config:/home/appuser/.config/fabric \
  kayvan/fabric:latest \
  --serve --api-key "$FABRIC_API_KEY"

The container runs as a non-root user; mount the config directory for persistent keys/patterns. See scripts/docker/ for building custom images.

6.3 Building from source

# CLI + server
go install github.com/danielmiessler/fabric/cmd/fabric@latest
# Helpers
go install github.com/danielmiessler/fabric/cmd/to_pdf@latest
go install github.com/danielmiessler/fabric/cmd/code2context@latest
go install github.com/danielmiessler/fabric/cmd/generate_changelog@latest

Build the web app (from web/):

cd web
pnpm install
pnpm build        # vite build; outputs the SPA
pnpm preview      # serve the built app

Regenerate Swagger docs after changing server annotations:

swag init -g internal/server/serve.go -o docs

6.4 Nix

The repo ships a flake.nix / flake.lock and nix/pkgs/fabric derivation for reproducible builds (nix build).

6.5 Day-2 operations

Task Command
Update built-in patterns fabric --updatepatterns
Change default model fabric --changeDefaultModel
Re-run setup / add providers fabric --setup
Inspect a session fabric --printsession <name>
Clean a session/context fabric --wipesession <name> / --wipecontext <name>
Check version fabric --version
Verbose diagnostics fabric --debug 4 ... (wire-level)

6.6 Observability

Logging is leveled via --debug (0 off → 4 wire). The server uses Gin's logger and recovery middleware (panics return 500). Token usage is available per request with --show-metadata (CLI) and via the usage SSE event (API). There is no built-in metrics endpoint; scrape the reverse proxy or wrap the binary for production telemetry.

6.7 Backup & restore

Everything stateful is under ~/.config/fabric/. Back it up as a unit:

tar czf fabric-config-backup.tgz -C ~/.config fabric

Restore by extracting to the same path. Custom patterns in CUSTOM_PATTERNS_DIRECTORY must be backed up separately if outside this tree.


7. REST API Reference

Base URL defaults to http://<host>:8080. Authenticated endpoints require X-API-Key when the server was started with --api-key.

7.1 Core endpoints (--serve)

Method Path Purpose
POST /chat Streaming chat completions (SSE). Body: {prompts:[{userInput,vendor,model,contextName,patternName,strategyName,sessionName,variables}], language, modelContextLength, ...ChatOptions}
GET /config Get masked provider config
POST /config/update Update provider keys/URLs
GET /models/names All models + per-vendor grouping
GET /patterns/names List pattern names
GET /patterns/:name Get raw pattern
POST /patterns/:name Save pattern
POST /patterns/:name/apply Apply pattern with {input, variables}
DELETE /patterns/:name Delete pattern
GET /patterns/exists/:name Existence check
PUT /patterns/rename/:oldName/:newName Rename pattern
GET/POST/DELETE/PUT /contexts/... Context CRUD (StorageHandler)
GET/POST/DELETE/PUT /sessions/... Session CRUD (StorageHandler)
GET /strategies List strategies (name/description/prompt)
POST /youtube/transcript {url, language?, timestamps?} → transcript + metadata
GET /swagger/*any Swagger UI + swagger.yaml (no auth)

7.2 Ollama-compatible endpoints (--serveOllama)

Method Path Purpose
GET /api/tags Patterns presented as Ollama "models" (<pattern>:latest)
POST /api/chat Ollama-format chat (maps model→pattern, supports num_ctx, variables)
GET /api/version Server version

The Ollama shim translates an Ollama request into a Fabric /chat request (the pattern name is the part of the model before :), proxies it, and reformats the streamed response into Ollama's NDJSON.

7.3 Example: apply a pattern over HTTP

curl -s http://localhost:8080/patterns/summarize/apply \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $FABRIC_API_KEY" \
  -d '{"input":"long text...","variables":{"role":"editor"}}'
{ "Name": "summarize", "Pattern": "...resolved system prompt..." }

8. Repository Structure

fabric/
├── cmd/
│   ├── fabric/             # main CLI + server entry point
│   ├── to_pdf/             # LaTeX → PDF helper
│   ├── code2context/       # code dir → JSON for create_coding_feature
│   └── generate_changelog/ # git/PR changelog generator (cobra + SQLite)
├── internal/
│   ├── cli/                # flag parsing + command handlers
│   ├── core/               # PluginRegistry + Chatter (composition + orchestration)
│   ├── domain/             # request/options/attachment/stream/thinking types
│   ├── chat/               # chat message primitives
│   ├── plugins/
│   │   ├── plugin.go       # Plugin interface, Settings, SetupQuestions
│   │   ├── ai/             # vendor clients (openai, anthropic, gemini, ollama, ...)
│   │   ├── db/fsdb/        # filesystem-backed patterns/contexts/sessions
│   │   ├── template/       # template engine, plugins, extensions
│   │   └── strategy/       # strategy loader/manager
│   ├── server/             # gin REST API + Ollama shim + Swagger
│   ├── tools/              # youtube, jina, spotify, converter, custom_patterns, ...
│   ├── i18n/               # translations + locale detection
│   └── log/                # leveled debug logging
├── data/
│   ├── patterns/           # built-in patterns (system.md per pattern)
│   └── strategies/         # built-in prompt strategies (JSON)
├── web/                    # SvelteKit web app
├── completions/            # zsh/bash/fish completion scripts + installer
├── scripts/                # docker, installer, pattern_descriptions, readme_updates, python_ui
├── docs/                   # docs + generated swagger
├── nix/                    # Nix packaging
├── go.mod / go.sum         # Go module
└── flake.nix / flake.lock  # Nix flake

9. Module Reference (developer internals)

Module Key files Responsibility
internal/cli cli.go, flags.go, help.go, chat.go, listing.go, management.go, setup_server.go, tools.go, transcribe.go, output.go Parse flags, route commands, build chat requests, format help (i18n), write output/clipboard/audio
internal/core chatter.go, plugin_registry.go Orchestrate a chat; compose vendors/tools; resolve model→vendor
internal/domain domain.go, attachment.go, stream.go, think.go, thinking.go, file_manager.go Core types and pure logic (message normalization, think-block stripping, file-change parsing)
internal/plugins plugin.go Plugin/Settings/SetupQuestion framework + env-var naming
internal/plugins/ai/* per-vendor *.go Vendor clients implementing the ai.Vendor interface
internal/plugins/db/fsdb patterns/contexts/sessions entities Filesystem CRUD + variable application
internal/plugins/template template.go, text.go, datetime.go, file.go, fetch.go, sys.go, extension_*.go, hash.go Template resolution, built-in plugins, extension registry/executor
internal/plugins/strategy strategy loader/manager Load JSON strategies, prepend prompt
internal/server serve.go, auth.go, chat.go, patterns.go, contexts.go, sessions.go, models.go, config*.go, strategies.go, youtube.go, ollama.go, storage.go Gin handlers, auth, SSE, Ollama shim, generic storage CRUD
internal/tools youtube, jina, spotify, converter, custom_patterns, githelper, lang, notifications External integrations and helpers

9.1 The ai.Vendor interface

Vendor clients implement (see internal/core/chatter_test.go mock): GetName, GetSetupDescription, IsConfigured, Configure, Setup, SetupFillEnvFileContent, ListModels, Send, SendStream, NeedsRawMode. Adding a provider means implementing this interface (usually atop plugins.NewVendorPluginBase) and registering it in NewPluginRegistry. OpenAI-compatible providers are added en masse from openai_compatible.ProviderMap.

9.2 Helper binaries

  • to_pdf (cmd/to_pdf): reads stdin or a .tex file, shells out to pdflatex -interaction=nonstopmode in a temp dir, and copies the resulting PDF to the destination. Validates pdflatex is on PATH.
  • code2context (cmd/code2context): scans a directory (depth/ignore options) or a stdin file list and emits JSON. -depth default 3, -ignore default .git,node_modules,vendor.
  • generate_changelog (cmd/generate_changelog): Cobra-based; walks git history and GitHub PRs (GraphQL), caches in SQLite (changelog.db), optional AI summaries via Fabric. Flags include --repo, --output, --limit, --version, --ai-summarize, --sync-db, --release, --incoming-pr, --process-prs.

10. Code Quality & Conventions

  • Error handling: Go idiomatic (value, error) returns; named returns used heavily in CLI handlers; the handler chain uses a (handled bool, err error) pattern for clean short-circuiting.
  • Internationalization: all user-facing strings go through i18n.T(); never hardcode English in new code.
  • Testing: extensive table-driven unit tests colocated as *_test.go (flags, template engine, plugins, server URL building, Ollama num_ctx parsing, file-change parsing, notification escaping). Vendor calls are mocked via the ai.Vendor interface.
  • Security-by-construction: path-traversal guards, size caps, content-type checks, hash-verified extensions, positional-argument shell invocation for notifications.
  • Separation of concerns: domain holds pure types/logic; core orchestrates; plugins integrate; server/cli are thin front ends over the same core.
  • Defaults discipline: generation defaults are constants in domain that must mirror the CLI struct-tag defaults.

10.1 Testing strategy

Run the Go test suite:

go test ./...

Notable suites: internal/cli (flag parsing, image validation, chat options), internal/plugins/template (template/plugin/extension behavior, sentinel handling), internal/server (buildFabricChatURL, parseOllamaNumCtx), internal/domain (ParseFileChanges, StripThinkBlocks, NormalizeMessages). Web app tests run under Vitest (pnpm test).


11. Potential Improvements & Tech Debt

Observations from the source, useful for maintainers and contributors:

  • Fetch allowlist: the fetch template plugin documents (in code comments) that production deployments should consider URL allowlists; none is built in. A configurable allowlist would harden patterns that fetch URLs.
  • CORS is dev-pinned: /chat hardcodes Access-Control-Allow-Origin: http://localhost:5173. A configurable allowed-origins list would ease non-default web deployments.
  • Two CLI flag systems: the main binary uses go-flags (struct tags) while generate_changelog uses Cobra. Intentional (separate binaries) but worth noting for contributors.
  • No server-side rate limiting / metrics: the API has no built-in throttling or metrics endpoint; rely on a reverse proxy.
  • Notification truncation: desktop notification truncation counts Unicode code points, not grapheme clusters (documented limitation — complex emoji may truncate oddly).
  • Unauthenticated default: the server runs without auth if --api-key is omitted (logged as a warning). Consider requiring an explicit --insecure flag to make the unauthenticated mode opt-in.

12. Troubleshooting (operational)

Error: Starting REST API server without API key authentication

  • Cause: --serve without --api-key.
  • Fix: Restart with --api-key. Until then the API is open.

Error: 401 Missing API Key / 401 Wrong API Key

  • Cause: Missing or mismatched X-API-Key header.
  • Fix: Send the correct header; if proxying, ensure the proxy forwards X-API-Key (see §6.1).

Issue: streamed responses arrive only at the end / buffered

  • Cause: Proxy buffering of SSE.
  • Fix: proxy_buffering off (nginx); Fabric already sets X-Accel-Buffering: no.

Error: could not find vendor (server or CLI)

  • Cause: Requested model not mapped to a configured vendor, or no default set.
  • Fix: Configure the provider (/config/update or fabric --setup); confirm with GET /models/names or fabric --listmodels; pass explicit vendor.

Error: swagger.yaml not found - generate it with: swag init -g internal/server/serve.go -o docs

  • Cause: Swagger spec not generated/shipped next to the binary.
  • Fix: Run swag init -g internal/server/serve.go -o docs, or place docs/swagger.yaml beside the executable.

Error: Ollama shim num_ctx must be ...

  • Cause: Invalid num_ctx in an Ollama /api/chat request (non-integer, negative, > 1,000,000, NaN/Inf, wrong type).
  • Fix: Send a positive integer ≤ 1,000,000, or omit it.

Error: extension config hash mismatch / executable hash mismatch

  • Cause: The extension's config or binary changed after registration (tamper detection).
  • Fix: Re-register with --addextension after vetting the change.

Issue: local OpenAI-compatible server returns empty/garbled responses

  • Cause: The server doesn't support OpenAI's Responses API.
  • Fix: --disable-responses-api (or disableResponsesAPI: true in config.yaml).

Diagnostics

fabric --debug 4 -p summarize "test"   # wire-level: logs exact messages to/from the model

13. Contributing

  1. Fork and clone; ensure a recent Go toolchain.
  2. Build: go build ./...; test: go test ./....
  3. Follow conventions: route user-facing strings through i18n.T(); add table-driven tests beside new code; keep domain pure and orchestration in core.
  4. New AI provider → implement the ai.Vendor interface and register it in NewPluginRegistry (or add to openai_compatible.ProviderMap if OpenAI-compatible).
  5. New built-in template plugin → add a plugin type and wire it into the plugin: switch in template.go.
  6. Server changes → update Swagger annotations and regenerate with swag init.
  7. Web changes → cd web && pnpm lint && pnpm check && pnpm test.
  8. Patterns → add a system.md under data/patterns/<name>/.

The project is MIT-licensed; the canonical repository is https://github.com/danielmiessler/fabric.


14. Quick Reference

Key paths

Path Contents
~/.config/fabric/.env API keys + defaults
~/.config/fabric/config.yaml YAML defaults
~/.config/fabric/patterns/ Built-in patterns
~/.config/fabric/strategies/ Strategy JSON
~/.config/fabric/contexts/ Contexts
~/.config/fabric/sessions/ Sessions
~/.config/fabric/extensions/extensions.yaml Extension registry
$CUSTOM_PATTERNS_DIRECTORY Private custom patterns

Server commands

Command Effect
fabric --serve --api-key K REST API on :8080
fabric --serve --serveOllama --api-key K + Ollama endpoints
fabric --serve --address :9000 Custom bind address

Critical env vars

Var Purpose
OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, … Provider auth
OLLAMA_URL, LM_STUDIO_API_BASE_URL Local provider URLs
CUSTOM_PATTERNS_DIRECTORY Private patterns
DEFAULT_VENDOR / DEFAULT_MODEL Defaults
FABRIC_MODEL_<PATTERN> Per-pattern model (`vendor
GITHUB_TOKEN generate_changelog

REST endpoints at a glance

POST /chat · GET/POST /config[/update] · GET /models/names · */patterns/* · */contexts/* · */sessions/* · GET /strategies · POST /youtube/transcript · GET /swagger/* · (Ollama) GET /api/tags · POST /api/chat · GET /api/version