Dustin Stringer185 downloadsDeploy an advanced Orchestrator-Worker multi-agent framework to automate vault indexing, template generation, and interactive sidebar chat functions.
Command Center is a personal operational OS for Obsidian — a local-first AI multi-agent orchestrator that turns your vault into a single, navigable control room. One dashboard gives you a zero-token “happening now” snapshot of today's note, unfiled captures, open tasks, and managed workspaces; a calendar for creating and completing dated work; a doorway that jumps to any note, folder, tag, or Bases view; and a Markdown-backed Command Deck that turns your workflow files into one-click buttons. Behind it sits a 13-provider routing layer, a local Pi ReAct engine with Orchestrator–Worker loops, hybrid vault RAG (BM25 + semantic retrieval), persistent agent memory, native Markdown/Canvas workflows with Bases queue integration, voice input and live transcription, extensible MCP and REST connectors, and headless automation — all behind an absolute write gate, and all without imposing a productivity framework on your notes.
[!IMPORTANT] Command Center can modify vault files when you approve or run mutating operations. Keep backups, review destructive action cards, and test workflows on non-critical notes first.
Most AI integrations add a chat box. Command Center adds an operational layer:
_index.md files describe folder purpose and direct-child contents so agents can route work without repeatedly scanning the whole vault.Every feature in Command Center answers to one of six principles. They are design constraints, not slogans: each one names the code that enforces it, so a claim in this README can be checked against the implementation.
No agent writes to your vault without your explicit approval.
Implemented in src/security/WriteGate.ts. gateTools() wraps every capability handed to a model so authorization happens inside the tool's execute path — a forgotten check at a call site cannot bypass it, because there is no ungated route to a tool. getGatedTools() is the only sanctioned way to obtain capabilities. Mutations surface as proposals with target paths and diffs; protected paths override even the global Auto write toggle, matched prefix-exactly so Vault/Private never captures Vault/PrivateNotes. Every decision — approved, rejected, timed out, or auto-approved — lands in an append-only log on the dashboard. Dashboard task edits abort if the target line changed while awaiting approval, and success is reported only after the write completes.
Situational awareness must never cost a token.
Implemented in src/intelligence/VaultDataBridge.ts, following Dataview's model: read only Obsidian's metadataCache and cachedRead, never a model. It powers the four “Happening now” cards, the calendar, and the vault doorway. One snapshot feeds every surface, in-flight scans are shared rather than duplicated, and results are bounded (25 captures, 200 tasks) so a large vault cannot stall the UI. Model spend is reserved for actual reasoning — dashboards are free.
Your vault is the configuration. Extend the plugin by writing notes, not by editing settings JSON.
Implemented in src/ui/CommandDeck.ts, src/ui/CustomCards.ts, and src/connectors/ApiConnectorManager.ts. Workflow files become deck buttons, and any note carrying cc-card: true becomes a dashboard card — discovered, not registered. Both hot-register on vault events with no Obsidian restart. New tools, MCP servers, and REST connectors join the same CapabilityRegistry at runtime. Connectors are strictly declarative: a validated method, path, and schema, never downloaded code.
You can always see what the system did, what it is about to do, and what it cost.
Implemented across the ReAct monitor, the write-gate log, and the provenance line on every intelligence card (scan time plus “no tokens used”). Panels state their data source and say plainly when they are unconfigured or empty rather than rendering a misleading blank. Failures degrade visibly with the actual error text — no silent blanking, no frozen panel. Action blocks are stripped from visible chat, executed through real APIs, and confirmed back into model context, so the transcript reflects what actually happened rather than what was merely claimed.
Use what Obsidian already provides instead of reimplementing it.
Writes go through Vault.process, which is atomic and compatible with native File Recovery. Tasks use standard Markdown checkboxes with inline fields, so Dataview, Tasks, Kanban, and Bases keep working on whatever Command Center produces. .base views render through Obsidian's own renderer; folders reveal in the native file explorer; tag searches hand off to the built-in global search; card bodies render via MarkdownRenderer, so embeds, callouts, and Dataview blocks work unchanged. Styling uses Obsidian theme variables throughout, so the plugin inherits your theme rather than fighting it.
One surface for recording, finding, deciding, and acting.
The dashboard is a doorway, not a destination: dates, tasks, notes, folders, tags, Bases views, and workflows are all reachable and actionable from one responsive grid. The vault doorway jumps anywhere in the vault; the calendar creates and completes dated work; the embedded browser keeps documentation beside your notes, expandable inline or poppable into its own pane. Every panel is reorderable, resizable, and hideable per vault, and each one states its purpose and next action so nothing needs to be guessed.
[!NOTE] Principles 1 and 2 sometimes constrain features that would be easier to build otherwise — that is intentional. A dashboard that quietly spends tokens, or an agent that writes without asking, would be more convenient and less trustworthy.
Command Center exposes one dispatch layer across 13 providers:
| Provider | Type | Notes |
|---|---|---|
| Pi Daemon | Local companion | Serialized Pi JSONL RPC; keyless at the plugin boundary |
| OpenAI | Cloud | GPT/o-series, vision, embeddings |
| Anthropic | Cloud | Claude, tools, prompt caching |
| Google Gemini | Cloud | Multimodal, long context, cached-content support |
| OpenRouter | Cloud gateway | Multi-model OpenAI-compatible routing |
| Ollama | Local | Local chat, keep-alive lifecycle controls, and optional bearer authentication |
| Groq | Cloud | Low-latency inference and transcription-compatible routing |
| DeepInfra | Cloud | Hosted open-weight models |
| Mistral AI | Cloud | Mistral, Codestral, and Voxtral families with native STT/TTS (/v1/audio/transcriptions, /v1/audio/speech). |
| Cohere | Cloud | Command models for RAG with native STT (/v2/audio/transcriptions). |
| LM Studio | Local | Dynamic native model resolution, resource-aware JIT loading, OpenAI-compatible inference, and optional bearer authentication |
| xAI (Grok) | Cloud | Grok models with vision, tools, native STT (/v1/stt), and TTS (/v1/tts). |
| Custom Endpoint | Local or remote | User-defined OpenAI-compatible service with optional bearer authentication |
Routing classifies work as coding, vision, reading, reasoning, or fast. Capability checks prevent invalid model selection; optional exponential moving averages optimize initial routes for latency, cost, or a balanced objective. Recovery remains reliability-first: authentication and invalid-request failures fail or fall through immediately, while rate limits, network errors, timeouts, and server errors use isolated circuit breakers, bounded backoff, and a configurable multi-tier fallback chain.
Additional provider capabilities include:
/models endpoint on startup, covering chat, STT, and TTS model resolutionPOST /api/v1/models/download with progress tracking/api/v1/models: reuse a loaded primary LLM or select the smallest downloaded non-draft conversational model, excluding embedding and speculative draft modelsThe ReAct runtime follows an Orchestrator → Worker → Observation → Correction loop:
Built-in worker profiles cover orchestration, retrieval, summarization, and structural editing. ReAct-capable profiles (react-orchestrator, react-analyst) extend these with iterative reason-act-observe loops. Five standard agent roles—Orchestrator, Triage, Indexer, Health, and System Architect—bind each operational responsibility to a compute tier and least-privilege tool ceiling, and the runtime can create constrained custom roles without granting tools outside the parent worker's ceiling.
The codebase uses three distinct, layered vocabularies — they are intentionally not collapsed, because each keys a different table:
WorkerProfileName (src/types.ts) — the 4 static prompt+token configs in src/workers/: orchestrator, retriever, summarizer, editor. Smallest and most stable.AgentWorkerProfile (src/execution/ExecutionRouter.ts) — a superset adding react-orchestrator and react-analyst, the ReAct-capable profiles that have no static prompt entry but declare an execution modality (text/embeddings/…).StandardAgentRole (src/engine/AgentTypes.ts) — the 5 operational roles above; each maps to a compute tier + a worker profile + a TaskType via AGENT_TAXONOMY. Task.workerRole reuses this union.The pi-daemon string is a sentinel, not a profile: command-palette local tasks set workerProfile: 'pi-daemon' to route directly to the local Pi daemon via router.routeDirect.
Operational safeguards include:
Command Center can ground model calls in vault content without rebuilding the index on every query:
Persistent agent memory stores facts, preferences, entities, and session summaries in vault-native state. Semantic duplicate updates, thematic session hubs, threshold-aware pruning, and bounded prompt injection keep memory useful without allowing it to grow without control.
Command Center acts as a Metacognitive Partner: it helps users examine and negotiate how their own system works rather than grading it against a generic productivity framework. Discovery follows two deliberate stages:
The metacognition layer builds supporting local context without reorganizing or rewriting user notes:
TopographySweep uses Obsidian's TAbstractFile, TFile, TFolder, MetadataCache, and getAllTags APIs to map folders, tag frequencies, links, and hub/MOC candidates..obsidian and .trash, and writes only .obsidian/plugins/command-center/vault_topography.json.user_logic_profile.json.##/### boundaries, source lines, frontmatter tags/aliases, and outbound [[wikilinks]].embeddings modality through the Native Auto-Router and Python execution boundary. The shipped Python worker is a secure transport stub and reports that no embedding backend is configured; an integrated backend must return normalized, dimension-validated vectors before they can be stored.Workflows are vault-native rather than hidden in a remote service:
eval{{inputs.*}} and {{steps.*.result}}The Command Center Queue integrates with Obsidian Bases. It consumes native evaluated results, preserves filters/formulas/sorts/limits, excludes terminal notes, supports selection and bounded concurrency, and writes agent_status, score, and timestamp fields through processFrontMatter() so active Bases views refresh in real time.
The interview becomes the source of truth for daily operations:
_index.md manifests maintained from direct-child scansStationary indexes contain purpose, scope, summary, and status metadata. Compact purpose headers allow routing to the correct folder before deeper retrieval, reducing full-vault reads and prompt waste.
The full-page Command Center Dashboard is the single operational interface for Socratic vault discovery, onboarding, agent monitoring, queue control, approvals, and daily operations. Discovery is a dashboard mode—not a separate deck, pane, or modal. It begins with a contextual baseline before introducing read-only TopographySweep evidence. Topology remains supporting evidence and is never promoted into a rule without user confirmation.
Logic Discovery uses bounded generation and disables model reasoning where supported so the dashboard presents one concise visible question at a time. With LM Studio enabled, Command Center discovers native catalog state through /api/v1/models, prefers an already loaded primary conversational model, or JIT-loads the smallest suitable downloaded model before calling /v1/chat/completions.
Open Command Center from the ribbon or run Command Center: Start Setup / Onboarding Interview. Both routes use the same full-page dashboard.
Command Center now supports the Model Context Protocol for discovering and executing external tools from MCP servers. Add MCP server URLs in settings to make their tools available to the LLM during inference:
tools/list — tools are wrapped as ToolDefinitions/api/v1/mcpStandard and Python-backed agent work crosses a mandatory execution boundary:
NativeAutoRouter reads the shipped model_matrix.json and applies the global 1–10 quality/cost depth to text, image, audio, video, and embedding intents.shell: false, bounded output, cancellation, timeouts, cleanup, and circuit breaking. Credentials are never placed in argv or environment variables.DataNormalizer is the trust boundary for provider responses, Python results, intermediate observations, and multi-agent merges. It sanitizes tracebacks, stderr, malformed JSON, control characters, and oversized output before UI or vault use.Run Command Center: Run Shadow-Clone Diagnostics from the command palette to verify credential-memory wiping, current slider/matrix routing, fail-safe local routing, and Python-output sanitization. The harness uses in-memory fixtures and prints a sanitized report to the developer console; it does not modify user notes.
When enabled in settings, Command Center includes a server-side web search tool in requests routed through OpenRouter. The model can invoke web_search_call to pull live information from the web, with results and citations returned directly in the response. Controlled by the webSearchEnabled setting toggle.
The right-sidebar chat supports Quick, ReAct, and Workflow modes with:
@Note, @path, and .base context▊) on pending assistant messagesCommand Center now includes a Capability Registry — a central, discoverable surface for every instrument the agent can invoke. Instead of the orchestrator pre-selecting which tools to use, the model can autonomously reason about which capability serves each task:
@-command aliases.@-command aliases (e.g., @vault, @websearch, @composer, @memory) so users can invoke tools explicitly.always (always included in context), autonomous (model may decide), explicit (only on user request).never, on-threshold, or always for destructive operations.describeEnabled() produces a compact inventory of available capabilities for the model's context window.Projects are focused AI workspaces with isolated chat history, per-project model configuration, and scoped context sources:
.md file under .command-center/projects/ with YAML frontmatter — no hidden databases or external services.The composer provides a three-stage fuzzy matching engine for precise text replacement:
Additional capabilities:
applyOperations() applies a sequence of insert, update, replace, and delete operations in order.The typeahead engine provides real-time suggestions as you type @ in the editor:
@vault, @websearch, @composer, @memory resolve to their corresponding capabilities.[[wikilink]] references.System prompts are stored as vault-native Markdown files with YAML frontmatter:
{{vault}}, {{date}}, {{time}}, {{user}}, {{style}}, {{memory}} are resolved at render time.Builds on the persistent agent memory store to provide user-facing memory operations:
remember() processes natural-language "remember that" commands.extractFromTurn() detects "I prefer", "I am", "remember that" patterns in conversation turns.buildProfile() aggregates stored facts into a structured UserMemoryProfile with name, style, expertise, and goals.recall() searches memories by relevance to a query and returns formatted Markdown.injectMemoryPrompt() produces a bounded memory context block for the model.Obsidian desktop
├── Command Center dashboard
│ ├── task queue, status, history, and frame-batched streaming
│ └── fixed-pool ReAct monitor, replay, export, and debug stepping
├── Right-sidebar chat
│ ├── Quick → ConversationManager → ProviderDispatcher
│ ├── ReAct → PiAgentDaemon → Orchestrator/Workers/Tools
│ └── Workflow → WorkflowEngine → provider or Pi routes
├── Interview-derived operations
│ ├── ConfigManager + generated style guide
│ ├── FolderIndexer → protected _index.md manifests
│ └── DailyEngine + InboxTriager + CapacityEngine
├── Metacognition and knowledge layer
│ ├── TopographySweep + dashboard LogicDiscovery → localized topology/profile JSON
│ ├── ChunkingEngine → H2/H3 chunks + tags/aliases/wikilinks
│ ├── DialecticRAG → normalized embedding ingestion → memory / injected SQLite-VSS
│ ├── HybridRetriever → BM25 + embeddings + weighted RRF
│ └── AgentMemoryStore/ReActMemoryBank → bounded persistent memory
├── Workflow layer
│ ├── Markdown/Canvas parser → validated DAG tiers
│ ├── Bases queue → bounded target batches
│ └── frontmatter state sync → live Bases refresh
├── Execution layer
│ ├── NativeAutoRouter → model_matrix.json + global depth 1–10
│ ├── ExecutionRouter → explicit worker modalities + secure credentials
│ ├── PythonWorkerTransport → bounded JSON-RPC subprocesses
│ └── DataNormalizer → sanitized results, observations, and merges
└── Provider layer
├── ModelRouter/ProviderDispatcher → capability, fallback, isolated circuits
├── cloud adapters → OpenAI, Anthropic, Gemini, etc.
└── local adapters → Pi, Ollama, LM Studio, custom endpoint
agent_end and agent_settled.0x0A before UTF-8 decoding, preserving split code points, CRLF, U+2028/U+2029, bursts, and final unterminated frames.requestAnimationFrame; trace history and visible rows are capped.Download the release assets or the packaged command-center directory.
Create this folder inside your vault:
<your-vault>/.obsidian/plugins/command-center/
Copy the plugin assets from release/command-center/:
command-center/
├── main.js
├── manifest.json
└── styles.css
Repository-level LICENSE and ATTRIBUTIONS.md remain published alongside the source and GitHub release documentation.
Restart Obsidian or reload community plugins.
Open Settings → Community plugins and enable Command Center.
Run Command Center: Start Setup / Onboarding Interview from the command palette.
Pi powers local palette tasks and the full multi-agent ReAct path. Install it separately:
npm install -g @earendil-works/pi-coding-agent
pi --version
Command Center auto-detects common global npm locations. On Windows it resolves pi.cmd to Pi's JavaScript CLI and launches it with the real Node executable to avoid Electron/Node wrapper issues. You can override the detected path in Settings → Command Center → Core Configuration.
Pi is an external MIT-licensed companion and is not bundled into this plugin.
Launch onboarding in the full-page dashboard from either the Command Center ribbon action or Command Center: Start Setup / Onboarding Interview. Discovery, confirmation, and synthesis stay in the central workspace instead of opening a separate setup modal.
The six configuration phases are:
A confirmation/synthesis stage then previews 2–4 templates and 2–3 workflows. Nothing is generated until you explicitly select and approve it.
The interview writes validated assets under .command-center/, including:
.command-center/
├── config.json
├── style-guide.md
├── templates/
└── workflows/
These are local runtime files and must not be published with the plugin. The repository includes a non-secret reference at docs/config.example.json.
Do not enter API keys, passwords, tokens, URLs, hosts, ports, or endpoint details into the interview. Secret-like input is rejected locally. Configure provider credentials and endpoints only in Settings → Command Center.
To start over, run Command Center: Reset / Re-Initialize Vault Configuration. Generated configuration and style files are moved through Obsidian's trash flow before onboarding restarts.
Open Settings → Command Center. The settings UI is organized into six sections.
Configure the active profile, token limits, Pi path, daemon startup, memory limits, Base batch concurrency, and Silent Daily Startup. Pi detection and status diagnostics are available here.
Configure text-to-speech enablement, speaking voice, speaking rate, speech-to-text enablement, transcription provider preferences, and automatic read-aloud behavior here. Chat and voice recording use the same speech settings.
Speech-to-text models are per-provider (STT model IDs are not portable across providers — openai/gpt-4o-mini-transcribe is an OpenRouter routing slug, grok-stt is xAI, whisper-1 is OpenAI). Set the slug each provider accepts in the per-provider model fields; a blank entry uses the provider's built-in default.
Text-to-speech can use the browser's built-in speech engine (default) or route through a provider's /audio/speech (or xAI /v1/tts) endpoint for higher-quality voices. Pick the engine in Text-to-speech engine; set a per-provider TTS model and voice id when using a provider engine.
Each provider has a collapsible card for enablement, endpoint configuration, health checks, and model refresh. API keys are not exposed through ordinary settings fields.
Select Manage API Keys to open the built-in secrets editor. Provider secrets are stored in Obsidian Secret Storage under the Command Center namespace, so they persist with your vault instead of a custom encrypted file. Existing secrets can be replaced or removed, but they are not revealed back into the UI.
Authentication metadata distinguishes required, optional, and unsupported credentials. LM Studio's Require Authentication token, authenticated Ollama proxies, and custom OpenAI-compatible bearer tokens all use Obsidian Secret Storage for persistence without making a key mandatory for ordinary local operation. Tokens are applied consistently to inference, streaming, model discovery, health checks, transcription, and local model lifecycle requests.
Credentials are resolved only at request time. Provider secrets stay in Obsidian's secret store, while interviews, generated workflows, CLI/URI arguments, subprocess argv/environment, logs, and repository examples continue to exclude credentials.
Assign a provider/model pair to each task class:
| Task class | Typical use |
|---|---|
coding |
Code generation, refactoring, technical edits |
vision |
Image and Canvas attachment analysis |
reading |
Long documents, synthesis, extraction |
reasoning |
Planning, analysis, orchestration |
fast |
Classification and low-latency transforms |
Live-discovered models appear with a network indicator. If discovery fails, the static registry remains available.
Enable or disable fallback, then add, remove, and reorder providers. Permanent request/schema errors fail fast; transient failures use backoff and reliability-ranked alternatives without allowing cost optimization to weaken recovery.
Review provider state, test one provider, refresh all providers, and inspect actionable errors such as a missing Pi binary or unreachable local endpoint.
Open Command Center from the ribbon or command palette. Every panel carries a one-line description of what it shows and what to do with it, so nothing needs to be guessed.
Happening now — four zero-token intelligence cards
Computed from Obsidian's metadata cache only; no model calls, no token spend.
| Card | What it shows | What to do |
|---|---|---|
| Daily intelligence | Today's note, its sections, tracked metrics, and any capacity rule that tripped | Click to open today's note |
| Capture | Notes you dropped in but have not filed | Open one to process it, or ask for triage |
| Action items | Open tasks vault-wide, in Kanban-style lanes (Overdue / Due today / Scheduled / Undated) | Click a row to jump to that exact line |
| Workspaces | Managed folders with live note counts, freshness, and index state, plus nested .base views |
Click to open a folder index or Bases view |
Calendar — a month grid marking which days have notes and how much work is scheduled. Click a date to open or create its daily note, tick tasks complete, reschedule them, delete them, or add new dated tasks. Every write is a proposal that passes the write gate first.
Vault doorway — one filter box across note titles, folders, tags, canvases, and .base views, ranked by prefix, word-boundary, then substring match. Press Enter to open the top hit. Left empty it lists your most recently edited notes. Folders reveal in the native file explorer; tags hand off to Obsidian's own global search.
Command deck — a vertical rail built from your vault's workflow files (.md, .canvas, and generated .json). Labels, descriptions, and icons come from native frontmatter, and new workflows hot-register without an Obsidian restart.
Browser — a real embedded web view for documentation, API references, and research. Use it inline, expand it to fill the dashboard for close reading, or pop it out into its own pane. Bare hosts and localhost:3000 resolve as addresses, free text becomes a search, and non-web schemes (javascript:, data:, file:) are refused. Hidden by default — enable it in Customize dashboard.
When Obsidian's core Web viewer is enabled, the panel offers to hand the current address to it, so browsing uses the history, favicons, ad blocking, and search engine you already configured in Obsidian rather than a parallel set of the plugin's own. Detection is guarded and falls back to the plugin's own view if the core viewer is off or refuses (src/ui/native-webviewer.ts).
On desktop this uses Electron's <webview>, the same mechanism as Obsidian's own Web viewer, so it browses the open web normally — including sites such as GitHub, MDN, Google, and Stack Overflow that send X-Frame-Options and would refuse to load in a plain iframe. Browsing state lives in its own isolated partition, separate from Obsidian's session. An Open externally button hands the current page to your system browser, which is the better route for logins, downloads, and anything needing a password manager.
The widget and the full-pane view are the same component, so behavior and fixes never diverge between them. Open browser reuses an existing browser leaf rather than opening a new split each time.
[!NOTE] Where
<webview>is unavailable, the panel degrades to a sandboxed iframe and says so in the panel. In that limited mode only sites that permit framing will load; most major sites will not. Command Center is desktop-only, so this is an edge case rather than the normal path.
[!IMPORTANT] This is a convenience reader, not a replacement for your browser. Sign-in flows are the weak spot: Google's login pages actively resist embedded browsers, and password managers and passkeys will not be available. Use Open externally for anything involving credentials — which is also the safer habit.
Any note in your vault becomes a dashboard card by adding cc-card: true to its frontmatter. There is no registry and no settings form: create the note and the card appears, delete it and the card is gone. Cards are reorderable alongside built-in widgets.
---
cc-card: true
cc-card-title: Morning review
cc-card-hint: What I committed to today
cc-card-icon: sunrise
cc-card-order: 1
---
## Focus
- [ ] Draft the quarterly summary
- [ ] Reply to the vendor thread
![[Active projects.base]]
| Key | Purpose |
|---|---|
cc-card |
Required. true marks the note as a dashboard card. |
cc-card-title |
Display name; falls back to name, title, then the filename. |
cc-card-hint |
One-line description shown under the title. |
cc-card-icon |
Obsidian icon id. |
cc-card-order |
Sort order relative to other cards. |
Card bodies render through Obsidian's own Markdown renderer, so embedded .base views, Dataview blocks, callouts, images, and transclusions all work. Checkbox lines become interactive rows: ticking one writes back to the source note through the write gate, and the arrow button jumps to that exact line. Checkboxes inside fenced code blocks stay as code samples rather than becoming buttons.
Also on the dashboard
Run Command Center: Open Chat Panel and choose:
Use @Note Name, @folder/note.md, an active editor selection, or a .base reference to attach vault context. Suggested recent/active notes appear as dismissible pills; only retained pills are sent.
Open a Markdown note and run Execute agent task on current note. This command explicitly routes through the local Pi daemon and starts it automatically when possible.
The write gate is the boundary between the model and your vault. It is not advisory: every capability handed to an agent is wrapped so the gate runs inside the tool's execution path. A missed check at a call site cannot bypass it.
Capability wants to write
→ gate describes the change as a proposal
→ proposal appears in Mutation approvals
→ you click Approve
→ only then does the write occur
Defaults and controls
| Setting | Default | Effect |
|---|---|---|
| Auto write (global bypass) | Off | Off: every mutation waits for your click. On: approved capabilities write immediately. |
| Protected paths | Empty | Vault-relative folders that always require an explicit click, even when Auto write is on. |
Protected-path matching is prefix-exact, so Vault/Private never accidentally captures Vault/PrivateNotes. Paths are yours to define; the plugin assumes no folder names.
Guarantees
Vault.process, so they are atomic and compatible with native File Recovery.A workflow defines typed inputs and steps. Every synthesized step declares an assigned agent, required compute tier, fallback policy, and action type. Dependencies form a DAG; unknown dependencies and cycles are rejected before execution.
Conceptual example:
---
workflow:
name: Review incoming note
inputs:
tone:
type: dropdown
options: [concise, detailed]
steps:
- id: inspect
assigned_agent: researcher
required_tier: tier1_local
fallback_policy: configured
action_type: read
prompt: "Inspect {{inputs.targetPath}} using a {{inputs.tone}} style."
- id: summarize
dependsOn: [inspect]
assigned_agent: writer
required_tier: tier2_reasoning
fallback_policy: configured
action_type: write
prompt: "Summarize: {{steps.inspect.result}}"
---
The exact accepted shape is validated by the native parser and may include input defaults, conditions, provider/Pi routing, and output metadata.
Open a Markdown workflow and run Export Active Workflow to Canvas. Parallel steps share a tier column, dependencies become directed edges, and executable step metadata is retained in text nodes.
A standalone .base file can reference a workflow. Open it and run Execute Workflow on Current Base Queue. Choose concurrency from 1–10 and an optional partial-run limit. Command Center:
This allows a Base to function as a live, self-draining agent queue.
The chat microphone and Command Center: Quick Voice Prompt use browser-native MediaRecorder:
@ mentions and active-selection context resolutionThe transcription fallback chain tries each enabled STT-capable provider in order (LM Studio, Ollama, Groq, OpenAI, DeepInfra, Mistral, OpenRouter, xAI, Cohere, Custom). Each provider uses its own model slug — set per-provider in Settings → Accessibility & Speech, or leave blank for the built-in default (whisper-1 for OpenAI, grok-stt for xAI, whisper-large-v3 for Groq, openai/whisper-large-v3-turbo for DeepInfra, voxtral-mini-latest for Mistral, openai/whisper-large-v3 for OpenRouter, cohere-transcribe-03-2026 for Cohere). A global model is no longer broadcast to every provider, so a foreign slug can no longer break a provider it wasn't meant for.
Audio is sent only to the transcription endpoint configured in your local settings. Review that provider's privacy policy before use.
Spoken output defaults to the browser's built-in speechSynthesis engine. When Text-to-speech engine is set to a provider (or Auto), Command Center routes the text through that provider's TTS endpoint instead:
POST /v1/tts (native, model grok-tts)POST /v1/audio/speech (model gpt-4o-mini-tts)POST /api/v1/audio/speech (routed slugs like openai/tts-1)POST /v1/audio/speech (Voxtral TTS)The returned audio plays through a hidden <audio> element. If the provider request fails, Command Center falls back to the browser engine so spoken output is never silently dropped. Set a per-provider TTS model and voice id (e.g. alloy, nova, coral) in Settings → Accessibility & Speech.
On Obsidian versions exposing native CLI registration:
command-center:morning
command-center:workflow
command-center:indexes
These handlers invoke service layers directly without opening views. They return structured JSON and use non-zero failure semantics. Morning automation assembles the configured note but never auto-approves inbox mutations.
Example shape:
obsidian command-center:morning --metrics '{"available_minutes":120}'
obsidian command-center:workflow --path '.command-center/workflows/example.md' --inputs '{}'
obsidian command-center:indexes
Consult your installed Obsidian CLI's command syntax because host invocation details may vary by version.
For hosts without native CLI registration:
obsidian://command-center?operation=morning
obsidian://command-center?operation=indexes
The URI and CLI boundaries reject credential arguments, unsafe vault paths, malformed/oversized JSON, and execution before onboarding is complete.
Command Center is local software, but it uses the network when you select a cloud model or transcription provider, refresh a remote model catalog, or connect to a network-hosted custom endpoint. Supported remote services include OpenAI, Anthropic, Google Gemini, OpenRouter, Groq, DeepInfra, Mistral AI, and Cohere; requests are used only to provide the model, embedding, discovery, or transcription feature you invoke.
The desktop-only plugin also accesses files outside the vault in two explicit cases: it launches the separately installed Pi CLI as a child process, and it may read image attachments referenced by absolute paths so they can be sent to your selected vision provider. Ordinary note, configuration, memory, workflow, and index operations use Obsidian's vault APIs.
No client-side telemetry or advertising is included. Command Center does not self-update; installation and updates are handled by Obsidian and GitHub releases.
Depending on the mode and context you approve:
@ attachmentsUse local Pi/Ollama/LM Studio/custom endpoints when content must remain on your network, and verify those services independently.
command-center namespace.DataNormalizer..gitignore excludes runtime config, memory, audit traces, topology, generated assets, logs, environment files, and release/build outputs.scripts/sanitize-repo.mjs scans repository and release content for common secrets, private keys, absolute local paths, private IPs, NULs, and tracked runtime state.Run before committing or publishing:
npm run sanitize # tracked + untracked public files
npm run sanitize:staged # staged Git blobs; suitable for pre-commit
npm run sanitize:release # repository plus current build/release assets
npm run package automatically performs the release scan after packaging. CI and release workflows also run the sanitizer.
This repository follows the official Obsidian plugin documentation for lifecycle, workspace, settings, commands, modals, events, vault access, and submission requirements. When changing code, prefer Obsidian-native APIs over custom replacements, clean up event handlers on unload, and keep desktop-only code paths explicit where the plugin depends on them.
git clone https://github.com/scrunchds/Command-Center.git
cd command-center
npm ci
npm run dev
npm run dev starts esbuild watch mode. Reload Obsidian after bundle changes.
| Command | Purpose |
|---|---|
npm run typecheck |
Strict TypeScript check (including security, metacognition, execution, and diagnostic layers) |
npm run lint |
Zero-warning ESLint gate |
npm run test |
167 core + 153 ReAct + 22 provider = 342 total |
npm run benchmark |
Produce the standardized 10-metric report |
npm run benchmark:check |
Enforce the 25% core regression threshold |
npm run sanitize |
Scan public repository files for PII/secrets/runtime data |
npm run sanitize:staged |
Scan staged blobs for pre-commit use |
npm run build |
Typecheck and build minified production JS/CSS |
npm run package |
Build, create a clean release folder, and sanitize it |
npx obsidian-plugin-validator . |
Run community-submission manifest and source checks |
npm run package recreates release/command-center/ from scratch and permits exactly:
main.js
manifest.json
styles.css
License and attribution documents remain at repository level. Restricting the installable directory to Obsidian's three production files prevents stale development or documentation files from leaking into the plugin package.
src/ui/layout-model.ts, ensureWidgetChrome()).dashboardLayout to the OnboardingConfig type in src/onboarding/OnboardingTypes.tssrc/onboarding/InterviewEngine.ts to ask about widget preferencessrc/main.tsThe OnboardingConfig already has a style.dailyNoteLayout field, so a style.dashboardLayout field would follow the same pattern.
The test suite currently contains 342 tests:
CI runs on Windows, macOS, and Linux across Node 20, 22, and 24 with:
Release automation repeats the validation, builds a clean three-file plugin package, attests artifact provenance with Sigstore attestations, verifies each published asset cryptographically, and creates a GitHub release. The package metadata and manifest version are currently 1.8.0, with Obsidian 1.13.0 as the minimum supported app version.
The local community-plugin validator currently passes with 0 errors.
Run:
pi --version
npm install -g @earendil-works/pi-coding-agent
Then use Settings → Command Center → Core → Pi harness path and click 🔍 Detect (or type a custom path). Detection is non-blocking; the button shows ⏳ Detecting… while it runs and reports ⚠️ Not found if the binary is still missing. Missing-binary errors fail fast rather than entering a retry loop.
Run Command Center: Start Setup / Onboarding Interview and complete confirmation/synthesis. Both .command-center/config.json and .command-center/style-guide.md must validate before operational services start.
Check that:
Open the Command Center dashboard, inspect the Mutation approvals card's target list and diff preview, then choose Approve & apply or Reject. Closing the dashboard rejects pending confirmations safely.
STT model IDs are per-provider. The error The model 'openai/gpt-4o-mini-transcribe' does not exist means a slug meant for one provider (here, OpenRouter routing) was sent to another (e.g. xAI). Fix it in Settings → Accessibility & Speech → Per-provider speech-to-text models: set the slug each provider actually accepts, or leave the field blank to use that provider's built-in default (grok-stt for xAI, whisper-1 for OpenAI, etc.). The global Speech-to-text model field is no longer broadcast to every provider — it only applies to providers that have no built-in default.
The provider processed the audio successfully but returned an empty transcript (near-silent input, background noise, or a Whisper silence-hallucination artifact that was stripped). Speak closer to the microphone, or switch the Speech-to-text provider to one with a higher-quality STT model. Recording shorter than 500 ms is treated as an accidental mic tap and never sent.
The following features have infrastructure stubs and are ready for implementation when needed:
Command Center includes static URL builders for OpenRouter's video generation API:
POST /api/v1/videos — submit a video generation requestGET /api/v1/videos/{id} — poll generation statusGET /api/v1/videos/{id}/download — download generated video/api/v1/models/user when they become availableisVideoFile()) are ready in image-utils.tsImage generation models are registered in the OpenRouter provider (openai/gpt-5-image, google/gemini-3.1-flash-image, etc.) and the getImageGenerationUrl() helper returns POST /api/v1/images/generations.
xAI's realtime API (GET /v1/realtime WebSocket) supports voice-in/voice-out and function calling. The XAIProvider class (src/providers/xai.ts) implements chat completions plus native STT (POST /v1/stt) and TTS (POST /v1/tts, GET /v1/tts/voices). TTS is now wired into the spoken-output pipeline via TtsAdapter (see Text-to-speech above); the WebSocket realtime transport remains a future addition.
The newer POST /api/v1/responses format is a future migration target alongside the existing chat completions endpoint. Adopting it would enable streaming reasoning tokens, server-side tools (web search, code interpreter, MCP), and compaction; no Responses endpoint is wired up today.
Command Center is free and MIT-licensed. If it improves your workflow and you would like to thank the developer, you can make an optional donation:
The same link is available as a branded Buy Me a Coffee button in the support card at the bottom of Settings → Command Center. Donations are optional, do not unlock features, and are not required for support or updates.
Command Center is released under the MIT License.
Third-party projects remain under their respective licenses. See ATTRIBUTIONS.md for the audited dependency inventory and distribution boundaries, including:
The lockfile audit found no GPL-family, SSPL, BUSL, or undeclared package licenses. Repository sanitization, credential-boundary checks, clean-room packaging, and provenance attestation are part of the publication workflow.
“Obsidian” is a trademark of Dynalist Inc. Command Center is an independent community plugin and is not endorsed by Dynalist Inc. or the Pi maintainers.