Synapse

Use a scoped secret in either shell mode

Create a vaulted value, approve its project mapping, compare one-command and ambient loading without ever printing it, and watch trust invalidate the moment the file changes.

Outcome and prerequisites

You will create a disposable value in the vault, map it to one project, and exercise both ways Synapse can hand it to something — without the value ever appearing on screen. Then you will break the approval on purpose and watch every path refuse.

Where the value actually lives

Worth being precise about before you start, because the whole design follows from it.

ThingStored where
The secret valueThe value store, and only there. That is vault.db — sealed, one envelope per secret, under the key in vault.key — or macOS Keychain if the machine is set to it. synapse vault backend says which.
Its name, its variable name, its account referencebrain.db, Synapse's SQLite database. Never the value.
Which variable a folder should get.synapse.yaml in the project, which holds a reference and never a value.
Whether that file is trustedA SHA-256 digest of its exact bytes, recorded when you approve it.

No secret value is ever written to brain.db, to YAML, to an MCP response, or to a log, and neither store keeps one in plaintext. A value is read out of the vault at the moment a child process is launched, and goes nowhere else unless you ask for it with synapse secret copy, which puts it on the clipboard and still never prints it.

  1. Create a vault and a value

    shell
    mkdir -p "$HOME/tmp/synapsetutorial"
    cd "$HOME/tmp/synapsetutorial"
    synapse vault create tutorial
    synapse secret set tutorial demo SYNAPSE_TUTORIAL_TOKEN

    Enter a disposable value at the hidden prompt and confirm it. A vault is an organizational label; the three arguments are the vault, the secret's name inside it, and the environment variable it will become.

    text
    Created vault tutorial
    Saved tutorial.demo in the encrypted vault

    Now list what exists. Metadata only — there is no command that prints a value, because there is no reason for one to exist:

    shell
    synapse secret list tutorial
    text
    tutorial.demo	SYNAPSE_TUTORIAL_TOKEN	scoped
  2. Map it to this folder and approve the file

    shell
    synapse scope init .

    Replace the generated .synapse.yaml with:

    yaml
    version: 1
    scope: project
    env:
      SYNAPSE_TUTORIAL_TOKEN: tutorial.demo
    deny: []

    tutorial.demo is a reference, not a value. This file is safe to commit — that is the point of it holding a reference. Look at the file, then approve its exact bytes:

    shell
    synapse scope status .
    synapse allow
    synapse status .
    text
    Allowed /Users/example/tmp/synapsetutorial/.synapse.yaml
    text
    Folder: .
    Available: SYNAPSE_TUTORIAL_TOKEN
    Ambient: ready
    /Users/example/tmp/synapsetutorial/.synapse.yaml [project · approved]

    Ambient: ready means a shell hook would activate here. It does not mean one is installed.

  3. Hand it to exactly one command

    This is the narrower of the two boundaries and the one to prefer. Verify presence without printing content:

    shell
    synapse run -- sh -c 'test -n "$SYNAPSE_TUTORIAL_TOKEN" && echo "tutorial token available"'

    The child prints only the fixed sentence. Confirm the parent shell was never touched:

    shell
    test -z "$SYNAPSE_TUTORIAL_TOKEN" && echo "parent unchanged"

    Synapse read the stored value, set it on that one child, and the child exited with it. Nothing was exported into your session.

  4. Activate the whole directory

    For a permanent setup, use Settings → Shell environments → Enable shell hook and open a new terminal. To try it immediately in this shell:

    shell
    # zsh
    eval "$(synapse hook zsh)"
    
    # bash: eval "$(synapse hook bash)"
    # fish: synapse hook fish | source

    The approved scope activates at once. Now walk in and out of it:

    shell
    test -n "$SYNAPSE_TUTORIAL_TOKEN" && echo "ambient token available"
    cd ..
    test -z "$SYNAPSE_TUTORIAL_TOKEN" && echo "ambient token unloaded"
    cd synapsetutorial
    test -n "$SYNAPSE_TUTORIAL_TOKEN" && echo "ambient token restored"

    All three print. Leaving the directory unloads exactly the variables the hook loaded — and if one of them had a value before activation, leaving restores that original value rather than unsetting it. The hook tracks which keys it owns precisely so it can put things back as it found them.

  5. Break the approval and watch everything refuse

    Approval is bound to the exact bytes of the file. A blank line is a different file:

    shell
    echo "" >> .synapse.yaml
    synapse status .
    text
    Folder: .
    Available: none
    Ambient: blocked
    /Users/example/tmp/synapsetutorial/.synapse.yaml [project · pending]
    warning: /Users/example/tmp/synapsetutorial/.synapse.yaml: Scope has not been approved

    Three things happen at once. Ambient mode unloads at the next prompt. synapse run refuses before launching anything. And synapse launch refuses to start a coding tool at all:

    shell
    synapse run -- sh -c 'echo should-not-run'
    text
    Error: vault scope is not ready:
    /Users/example/tmp/synapsetutorial/.synapse.yaml: Scope has not been approved

    It refuses rather than running with the variable missing, because a command that runs against a half-resolved environment fails in ways that look like success. Read what changed, then re-approve:

    shell
    synapse scope status .
    synapse allow

    Both presence tests work again. This is what makes a committed .synapse.yaml safe: a teammate's edit, or a malicious one, arrives untrusted and stays that way until a human looks at it.

  6. Prove that deny wins

    Scopes resolve from the root of your filesystem down to the current folder, so a narrower file can add variables. It can never add back one a broader scope denied. Move the variable into deny:

    yaml
    version: 1
    scope: project
    env: {}
    deny:
      - SYNAPSE_TUTORIAL_TOKEN
    shell
    synapse allow
    synapse status .

    Available no longer lists the name. Create a folder-level scope beneath this one that tries to map it again, approve that too, and it still will not appear. Deny is a ceiling, not a default.

  7. See why global is not the same as ambient

    A secret can be marked global, meaning it is available without any scope file naming it:

    shell
    synapse secret global tutorial.demo on
    synapse secret list tutorial
    text
    tutorial.demo is now global
    text
    tutorial.demo	SYNAPSE_TUTORIAL_TOKEN	global

    Now move to a folder with no .synapse.yaml at all and check:

    shell
    cd ~ && synapse status .
    text
    Folder: .
    Available: SYNAPSE_TUTORIAL_TOKEN
    Ambient: inactive

    Read those two lines together, because the difference between them is a deliberate safety property. The name is availablesynapse run here would provide it. But ambient is inactive: a shell hook will not load it, because an ambient environment never activates from a global mapping alone. Turning on a global secret cannot silently populate every shell you open.

    shell
    synapse secret global tutorial.demo off
  8. Check what a connected tool can actually see

    Go back to the tutorial folder and ask a connected coding tool to call vaultstatus. It reports the variable names available here, the trust state of each scope, and whether ambient mode is ready — and no values, because that tool has no code path that reads one.

    The same is true of a preview. synapse launch claude --print shows DEMO_TOKEN=<from the vault> rather than a redacted value, because a preview calls a different function that lists names and never opens the vault at all. There is no value in the process to leak.

Clean up

shell
synapse deny
synapse secret forget tutorial.demo
synapse vault delete tutorial
cd .. && rm -rf synapsetutorial
text
Forgot tutorial.demo
Deleted vault tutorial

The next prompt unloads the ambient value. Forgetting the secret removes the stored value and Synapse's record of it, from both stores rather than only the one in use — so a machine that has switched backends leaves nothing behind in the one it stopped reading.

What you can rely on

Next step

Continue with Keep one skill library across every tool to finish the daily driver level.