Core
pragma-core — pure host business logic for git, filesystem, exec, scratchpads, whiteboards, and fanout rules.
crates/pragma-core is the host's business-logic boundary: synchronous, no Tauri, no
I/O surprises. Core::handle_rpc implements exactly five RPC domains — filesystem,
git, exec, scratchpads, whiteboards — and returns UnsupportedMethod for everything else
(server- or desktop-owned). rpc.rs maps CoreError onto protocol error codes.
git (git.rs)
The worktree engine. Highlights:
- CreateWorktree —
git worktree add -b <branch> <path>from the parent, orsourceBranchto materialize an existingoriginbranch as a tracking worktree (fetch refspec +--track) — how stacked PR layers get local worktrees. - CreateWorktreeAt —
git worktree add -b … <commit>with commit validation: fanout attempts all branch from one captured base so their diffs are comparable. - Worktree location —
<project>/.pragma/worktrees/<id>; headless/fanout checkouts use uuid names. - Git exclusions —
ensure_pragma_excludedwrites.pragma/worktrees/and.pragma/scratchpads/into the repo's real$GIT_DIR/info/exclude(asking git for the common dir rather than assuming.git), migrates a legacy broad.pragma/entry, and is idempotent. - Inspect/stage/commit/discard — worktree changes (merge-base diffing), staging helpers, commits, merge-to-parent, PR file diffs, GitHub push/pull/sync/abort helpers, branch deletion, dirtiness.
- Every git subprocess goes through
process_env::git()so a GUI-launched host findsgitonPATH.
filesystem (fs.rs)
ListDir, CreateFile, CreateFolder, PathExists, HomeDir, ReadFile, WriteFile, ListFileNames, ReadBytes, ReadBytesRange, WriteBytes, Rename, Delete, PaletteSearch.
- Containment: every path resolves through
resolve_in_worktree, canonicalizing both sides withpragma_platform::path::canonicalize(neverstd's, whose Windows\\?\verbatim output breaks git and prefix checks). - Binary reads are chunked (4 MiB) with caller-driven paging — how the PDF viewer streams.
PaletteSearchis the command palette's file finder: bounded filename + smart-case literal search overgit ls-filesoutput, with deadlines and cancellation.
exec (exec.rs)
Bounded, concurrent command execution for setup/teardown scripts and the CLI's
tab exec. Setup/teardown runs get PRAGMA_WORKTREE_PATH, PRAGMA_PROJECT_PATH, and
PRAGMA_WORKTREE_ID in their environment.
scratchpads (scratchpads.rs)
The host-side parser the desktop, gateway, and CLI all agree on:
- Lists managed MDX documents under
.pragma/scratchpads/— files without the managedpragmaScratchpadfrontmatter line (or with an unknown version) are skipped, which is exactly why hand-written files are invisible. comments_path(file)is the sibling<file>.mdx.comments.json.detach_agentnulls the attachment fields — used by fanout promotion before attempt worktrees are deleted.
whiteboards (whiteboards.rs)
Durable, worktree-scoped Excalidraw boards, owned by the host rather than the checkout:
- SQLite storage (
whiteboards.dbin the server directory) with create, get, list, search (title and text elements), edit, and delete. - Scene JSON is stored losslessly — unknown Excalidraw fields survive a round trip — and edits carry the version they read, so a concurrent writer is rejected instead of overwritten.
viewrenders a PNG natively here, never through a canvas in a webview, which is what lets scratchpad embeds and the mobile client show the same diagram.
fanout (fanout.rs)
The pure rules the server's state machine calls: resolve_selector
(agent[.model[.reasoning]] against the catalog), attempt_branch
(fanout/<fanoutShortId>/<memberShortId>), short_id, derive_title (first prompt
line), aggregate_status (roll-up that never overrides finalize-owned states),
is_active, and promotion_path (scratchpad promotion naming on collision).
Project config resolution
.pragma/config.json reads are tolerant by design — absent, malformed, or typo'd
files fall back to defaults rather than failing a session. Terminal fields
(terminal.shell, backend, distro, hiddenDistros) resolve per field: project
scope first, then the home file, so a project that pins only shell still inherits the
global backend.