Skip to main content

Using SSG Across Multiple Projects

Most SigmaShake users don't have one tidy monorepo — they have a handful of unrelated project folders scattered across ~/code, ~/work, an external drive, wherever. This page explains exactly what SSG does when you point it at more than one of those folders, in plain terms, without re-deriving anything from source yourself.

The short version: you install once, and every project on the machine is covered. There's nothing to repeat per folder and nothing to "add" when you start a new project — SSG notices it automatically the first time you use an AI agent inside it.


One install, every project​

ssg init wires the governance hook into your AI agent host globally by default — it edits your host's global config (for example ~/.claude/settings.json for Claude Code), not a per-project file. That means one ssg init --client=<name> run covers every project directory on the machine, including ones that don't exist yet.

ssg init --client=claude-code

If you specifically want a hook scoped to only the current directory — say, a client engagement folder you don't want touching your personal rules everywhere — pass --project-only:

ssg init --client=claude-code --project-only

--project-only is the opt-in narrowing. The default, with no flag, is global.


Per-project daemons are automatic​

Even though the hook install is global, evaluation itself is scoped per project. Every project directory gets its own eval daemon and its own Unix socket, derived by hashing the resolved project root (the outermost ancestor with a .git, or the nearest ancestor with .sigmashake/.claude, or the working directory itself). That 12-character hash becomes the daemon's namespace, and the daemon's socket and pidfile live under <data dir>/run/<hash>/.

You never create, name, or manage these daemons yourself. Open an AI agent session in project A, then in project B, and each gets its own daemon on its own socket — they don't collide, and you don't configure anything to make that happen.


One user-global rules database, per-OS paths​

Here's the part that surprises people coming from a "one config per repo" mental model: there is exactly one rules database for your entire user account, not one per project. Every per-project daemon reads from and enforces the same database — rule loading has no workspace filter, so whatever rules exist in the DB apply to every project's tool calls, everywhere.

OSData directoryRules database
Linux~/.sigmashake/~/.sigmashake/rules.db
macOS~/.sigmashake/~/.sigmashake/rules.db
Windows%USERPROFILE%\.sigmashake\%USERPROFILE%\.sigmashake\rules.db

Two environment variables can move these paths if you need a non-default layout: SIGMASHAKE_HOME relocates the whole data directory, and SSG_DB_PATH relocates just the database file. Absent either, the location is derived from your OS home directory ($HOME on Linux/macOS, %USERPROFILE% on Windows).

Because the database is user-global, a rule you write while working in project A is enforced in project B too, the moment it's synced — there's no per-project isolation to opt into.


The user-global rules directory​

Beyond individual .sigmashake/rules/*.rules files that live inside a given project, there is also a standing, project-independent rules directory:

~/.sigmashake/policy/user/*.rules

Anything you drop here applies across every project on the machine, the same way the database itself does. It's loaded by both the reconcile path (ssg rule sync, which writes these rules into the user-global database the daemon reads) and the daemon-unreachable fallback path, so it's enforced whether or not the daemon happens to be running at the moment of a tool call.

Conflict resolution: if a rule ID in ~/.sigmashake/policy/user/ collides with a rule ID defined in a project's own .sigmashake/rules/, the project rule wins. This matches the merge order ssg policy list already shows you — project-scoped rules take precedence over user-global ones. Use the user-global directory for policy you want everywhere by default; use a project's own .sigmashake/rules/ when a specific project needs to override that default.


Files vs. the database — and when to sync​

.rules files on disk (both a project's own .sigmashake/rules/*.rules and the user-global ~/.sigmashake/policy/user/*.rules) are the human-authored source of truth — what you edit, review, and check into git for a given project. The database is what the daemon actually queries at evaluation time, because indexed SQLite lookups are fast enough for a sub-millisecond eval budget and re-parsing text files on every tool call is not.

Those two can drift. If you edit a .rules file and don't reconcile it, the daemon keeps enforcing whatever was already in the database. Run:

ssg rule sync

whenever you've hand-edited a .rules file (in a project or in the user-global policy directory) and want the daemon to see the change. ssg rule list and ssg policy list are the read-only ways to check what's currently loaded without changing anything.

One more thing worth knowing if you regularly hop between projects: syncing rules while working inside project B only reconciles the directories actually touched by that invocation (project B's own rules, plus the always-included user-global policy directory) — it does not remove file-backed rules that belong to project A just because you happened to run the sync somewhere else.


Putting it together​

A day working across three unrelated folders looks like this, with zero extra setup:

  1. ssg init --client=claude-code — done once, ever, on this machine.
  2. Open project A. SSG notices, hashes the project root, and starts a daemon scoped to that hash. Tool calls are evaluated against the one shared rules.db.
  3. Switch to project B. A second, independent daemon starts for B's hash. Same shared rules.db.
  4. Write a rule you want everywhere (say, "block writes to .env files") into ~/.sigmashake/policy/user/, then ssg rule sync. It's now enforced in A, B, and every future project.
  5. Project C needs a narrower exception to that same rule ID. Add the override to project C's own .sigmashake/rules/, sync, and C's copy wins there — A and B are unaffected.

Nothing above required you to re-run ssg init, re-authenticate, or copy a rules file between folders.


See also​