# muse bridge — CI Authentication & Usage ## Overview `muse bridge` provides bidirectional Git interoperability for Muse repositories. This document covers CI setup, environment variables, and usage patterns for automated mirror workflows. ## Environment Variables | Variable | Purpose | |----------|---------| | `MUSE_AGENT_KEY` | PEM-encoded Ed25519 private key (agent identity) | | `MUSE_AGENT_HANDLE` | Registered Muse agent handle | | `GIT_AUTHOR_EMAIL` | Override git commit author email for exports | | `GIT_AUTHOR_NAME` | Override git commit author name | | `GIT_COMMITTER_EMAIL` | Override git committer email | | `GIT_COMMITTER_NAME` | Override git committer name | ## `.muse/git-bridge.toml` — Bridge State File Bridge state is persisted in `.muse/git-bridge.toml`. It records the last successful import and export sync points. Add this file to `.museignore` to keep per-developer state out of the Muse object store: ``` # .museignore .muse/git-bridge.toml ``` ### Structure ```toml [last_import] git_sha = "abc123..." # 40-char SHA-1 of last imported git commit git_ref = "main" # git branch imported muse_commit_id = "sha256:..." # Muse commit ID created by import imported_at = "2026-04-14T10:00:00Z" [last_export] muse_commit_id = "sha256:..." # Muse commit ID that was exported git_ref = "muse-mirror" # git branch written to git_sha = "def456..." # git commit SHA created by export exported_at = "2026-04-14T09:55:00Z" ``` ## Subcommand Reference ### `muse bridge git-import` Import git commits into a Muse repository: ```bash muse bridge git-import /path/to/git-repo \ --branch main \ --incremental \ --attribution-map /path/to/authors.json \ --sign \ --json ``` ### `muse bridge git-export` Export a Muse snapshot into a git working tree: ```bash muse bridge git-export \ --git-dir /path/to/git-mirror \ --git-branch muse-mirror \ --git-remote origin \ --no-push \ --json ``` ### `muse bridge git-status` Show bridge state and drift counts: ```bash muse bridge git-status --git-dir /path/to/git-repo --json ``` Output: ```json { "last_import": {"git_sha": "...", "git_ref": "main", ...}, "last_export": {"muse_commit_id": "sha256:...", "git_ref": "muse-mirror", ...}, "drift": { "git_commits_since_import": 3, "muse_commits_since_export": 1 } } ``` ### `--watch` mode Poll Muse HEAD every N seconds and auto-export on new commits: ```bash muse bridge git-export \ --git-dir /path/to/git-mirror \ --git-branch muse-mirror \ --no-push \ --watch 30 \ --json ``` Each poll emits a NDJSON event: ```json {"event": "poll", "muse_commit_id": "sha256:...", "changed": false} {"event": "exported", "muse_commit_id": "sha256:...", "git_sha": "abc..."} ``` ## GitHub Actions Example ```yaml name: Mirror to Git on: push: branches: [main] jobs: mirror: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install muse run: pip install muse-vcs - name: Export to git mirror env: MUSE_AGENT_KEY: ${{ secrets.MUSE_AGENT_KEY }} MUSE_AGENT_HANDLE: ${{ secrets.MUSE_AGENT_HANDLE }} run: | muse bridge git-export \ --git-dir /tmp/git-mirror \ --git-branch muse-mirror \ --git-remote origin \ --no-push \ --json ``` ## CircleCI Example ```yaml version: 2.1 jobs: mirror-to-git: docker: - image: cimg/python:3.12 steps: - checkout - run: name: Install muse command: pip install muse-vcs - run: name: Export Muse snapshot to git mirror command: | muse bridge git-export \ --git-dir /tmp/git-mirror \ --git-branch muse-mirror \ --git-remote origin \ --no-push \ --json environment: MUSE_AGENT_KEY: << pipeline.parameters.muse_agent_key >> MUSE_AGENT_HANDLE: muse-ci-bot workflows: mirror: jobs: - mirror-to-git: filters: branches: only: [main] ``` ## Attribution Map When importing git commits, map git author emails to Muse handles: ```json { "alice@example.com": "alice", "bob@example.com": "bob", "ci-bot@company.com": "ci-bot" } ``` Unmapped emails receive a synthetic handle: `git-import/`. Pass the map file with `--attribution-map`: ```bash muse bridge git-import /path/to/git-repo \ --attribution-map /path/to/authors.json \ --sign \ --json ``` ## Security Notes - All subprocess calls use argument lists — `shell=True` is never used. - `--git-branch` is validated against a safe-character regex before any subprocess call. Characters `;`, `&`, `|`, `` ` ``, `$`, `(`, `)`, spaces, and control chars are rejected. - Git SHA-1 values are validated (40 lowercase hex chars) before being passed to `git cat-file`. Invalid SHAs raise `ValueError` rather than reaching the subprocess. - Attribution handles are stripped of ASCII control characters on load. - Bridge state is written atomically (temp-file + rename) with a module-level lock. - `muse_commit_id` values are validated for the `sha256:` prefix at the persistence boundary — bare hex strings are never stored.