User guide: contents

Access from other computers

By default the Foundry answers only on the Mac it runs on. Colleagues can reach it from their own computers when you set three things in Settings → Network (or in config.yaml):

server:
  listen: 127.0.0.1              # 127.0.0.1 (default), ::1, 0.0.0.0 or ::
  allowed_hosts: [mymac.local]   # names people type; a port is optional
  allow_insecure_http: false     # true: also accept plain HTTP from other computers
  • listen is the address the server binds. 0.0.0.0 and :: answer on every network; the other two only on this Mac. Only these four values are allowed. A change needs a restart.
  • allowed_hosts replaces the old fixed localhost check. localhost, 127.0.0.1 and [::1] (with the server port) always work. Any other Host header must be listed, else the answer is 403 forbidden host. A change applies at once.
  • allow_insecure_http is off by default. A change applies at once.

The safe way: HTTPS through Caddy on the Mac. The Foundry has no TLS of its own. A proxy on the same Mac does the HTTPS and talks to the Foundry on 127.0.0.1.

  1. Keep listen: 127.0.0.1. Add the Mac's name to the allowed host names. Use the local host name from System Settings → General → Sharing, for example mymac.local. Colleagues must be able to resolve that name (macOS does it on the same network; other systems may need a DNS or hosts entry).
  2. Install Caddy: brew install caddy.
  3. Write the Caddyfile. Homebrew's service reads $(brew --prefix)/etc/Caddyfile:
    mymac.local {
        tls internal
        reverse_proxy 127.0.0.1:4777
    }
  4. Start it: brew services start caddy (it starts again at login). After a change: brew services restart caddy. To try it once in a terminal: caddy run --config <file>.
  5. Trust the certificate on the Mac itself: caddy trust.
  6. Give your colleagues Caddy's root certificate, root.crt. Caddy keeps it in its data folder, by default ~/Library/Application Support/Caddy/pki/authorities/local/root.crt when it runs as your user. Check that the file exists on your Mac. On macOS, open it with Keychain Access, add it to System, then set it to Always Trust. On Windows, import it into Trusted Root Certification Authorities. Firefox has its own certificate store.
  7. Check it:
    • curl --cacert root.crt -sI https://mymac.local/ shows 200 and strict-transport-security.
    • curl -s -H 'Host: mymac.local' http://127.0.0.1:4777/ answers HTTPS required.

What any proxy must do.

  • Run on the same Mac and connect to 127.0.0.1:<port>. The Foundry believes forwarded headers only from a connection that comes from this Mac.
  • Pass the Host header unchanged, with its port.
  • Set X-Forwarded-Proto itself from the real connection (overwrite what the client sent, never pass it on) and send X-Forwarded-For.
  • Not buffer responses (the run log is a stream).

Caddy does all of this by default. For nginx use proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_buffering off; ($host drops the port, so use $http_host). A proxy that rewrites Host to 127.0.0.1:4777 and sends no forwarded headers makes remote requests look local; do not use one.

Plain HTTP on a trusted network. Set listen: 0.0.0.0, add the Mac's name or address to the allowed host names and switch on allow_insecure_http. Warning: passwords and session cookies then cross the network unencrypted. Use it only on a network you trust.

What the server does.

  • Over HTTPS (through the proxy) the session cookie is Secure and responses carry Strict-Transport-Security (one year).
  • Every response carries a strict Content-Security-Policy (only this server's own scripts and styles) and X-Content-Type-Options: nosniff.
  • A change (POST, PUT, DELETE) with an Origin header must come from exactly the address you used: same scheme, name and port.
  • Requests from other computers are refused with HTTPS required unless they come through the proxy over HTTPS, or allow_insecure_http is on.
  • The server does not start on 0.0.0.0 or :: until an admin account exists.
  • The first admin can only be created on the Mac itself, not through the proxy.
  • Settings cannot be saved if the change would lock out the browser that saves it (its host name removed, or a listen value that does not cover the address it is connected to).
  • Sign-in and set-password also wait per client address (from the 5th wrong try, up to 60 seconds; see "Wrong passwords" in Settings and safety) and run at most 16 password checks at the same time; an e-mail longer than 254 characters is a wrong sign-in.

Restart after changing the address: stop and start scf ui, or run scf service install again.

Do not mix HTTPS and plain HTTP on one host name: HSTS makes browsers refuse HTTP for that name for a year.

A user account can only use Runs and the calls in "Roles and permissions" above, but a run can still run commands on this Mac, so only give accounts to people you trust. Links in Slack and notifications still point at http://localhost:<port>.

Stored credentials. A token or an ssh key can be stored through the API (POST /api/credentials); there is no UI page yet, and runs do not use them yet. They are kept in credentials.json in the data folder (mode 0600), encrypted with AES-256-GCM. The key is not in the data folder: it is in the macOS Keychain, as an item of the service claude-factory-credential-key. Only macOS is supported. The token or deploy key of a repository is stored here too, as repo:<repository id>; your own names must not start with repo:. The public key of a deploy key is not a secret: /api/repos always shows it in full, even when a stored secret is part of it (the rest of the answer is hidden as before).

  • What the API shows. Only type, name, created, last used and the fingerprint, never the secret. A token must be 8 to 4096 printable ASCII characters on one line. To check a fingerprint: printf %s "$TOKEN" | shasum -a 256, the first 16 digits.
  • Redaction. A stored secret is replaced by [redacted] in step output, logs, transcripts, errors and API answers. Limits: text written before a credential was saved stays on disk (the API hides it), the task text and other encodings (such as base64 of user:token) are not matched. If credentials exist and the Keychain is locked or the key is gone, runs fail before they start and the API shows nothing until that is fixed.
  • Deleting. Deleting a credential or a user (scf user delete) replaces the key, so older copies of credentials.json are useless. scf credential rotate-key does the same on demand.
  • Who can read the key. Anyone who runs commands as your macOS user, flow steps included. The encryption protects copies of the data folder: backups, sync, another user.

Global settings are stored in ~/.spaghetti-code-foundry/config.yaml; runs in ~/.spaghetti-code-foundry/runs/.


Improve this page on GitHub