{
  "markdown": "<div align=\"center\">\n\n# Phosphor\n\n**A macOS terminal that also runs your servers.**\n\nShell, Docker, metrics, keys and files — over one SSH connection per host.\nUnlocked with your fingerprint. Green on black, because that is how it should look.\n\n*SSH client · Docker manager · server monitor · SFTP · `authorized_keys` editor ·\nMCP server for Claude Code and Claude Desktop · macOS 26 · Swift 6 · MIT*\n\n</div>\n\n![Terminal](docs/images/01-terminal.png)\n\n---\n\n## The problem\n\nYou keep four windows open to do one job. A terminal for the shell. A second\nterminal for `docker logs -f`. A third for `htop`. A browser tab for whatever\ndashboard someone installed on the box. Each of them logs in separately, each\none asks for the key passphrase again, and none of them knows what the others\nare looking at.\n\nPhosphor opens **one SSH connection per host** and multiplexes everything\nthrough it — the interactive shell, container logs, `docker` commands, `/proc`\nsnapshots, SFTP transfers, port forwards. One login. One tunnel through your\nproxy. One place where the state lives.\n\nAnd because that state is already in the app, it also exposes an **MCP server**:\nClaude Code and Claude Desktop can use your servers through your connections,\nyour keys and your access policy — with every call written to an audit log.\n\n---\n\n## What it does\n\n### Docker, without leaving the terminal\n\n![Docker](docs/images/02-docker.png)\n\nThe container list is a sidebar, not a separate app. Inspect, stats, mounts,\nenvironment and live logs with `--tail` and a filter, streamed over the SSH\nconnection you already have. Environment values whose name looks like a secret\n(`PASS`, `KEY`, `TOKEN`, `SECRET`) are masked in the UI and never copied into\nthe audit log.\n\nNo Docker Engine API to expose, no socket to tunnel: it shells out to `docker`\nwith JSON output, which works on every box where Docker already runs.\n\n### Metrics that cost one channel\n\n![Metrics](docs/images/03-metrics.png)\n\nPer-core load, memory with the cache broken out, disks, network, and per\ncontainer CPU and memory — from `/proc` snapshots taken over a single\nlong-lived channel. No agent to install on the server, no swarm of exec\nchannels. Polling stops when the window is hidden, and every buffer has a\nceiling.\n\n### Hosts, groups and tags\n\n![Hosts](docs/images/04-hosts.png)\n\nOne group per host, as many tags as you like. The group carries the settings —\nhow to reach it, which key, which theme, what MCP is allowed to do — and tags\nare just for finding things. Import `~/.ssh/config` and keep going.\n\n### Unlock with a fingerprint\n\n![Touch ID](docs/images/05-touch-id.png)\n\nPhosphor has no account and no password of its own. There is a profile on this\nMac, and your fingerprint opens it. Passwords, passphrases and TOTP seeds live\nin the Keychain behind biometrics; keys can live in the Secure Enclave, where\nthey cannot be copied off the machine at all. Risky actions ask again.\n\n### A new server, set up by a recipe\n\n![Provisioning](docs/images/06-provisioning.png)\n\nConnect to a fresh box and Phosphor probes it: what is installed, what is\nlistening, whether anyone has been here before. If it is empty, it offers a\nrecipe — packages and unattended upgrades, Docker with log size caps, nginx,\ncertbot, a firewall that only opens 22/80/443, and finally disabling password\nlogin. Every step is idempotent, every step shows the exact commands, and the\nlockout guard means password login is closed only after a second key-based\nconnection has proved it works.\n\n### Keys you can actually see\n\n![Keys](docs/images/09-keys.png)\n\n`authorized_keys` as a table instead of a text file: fingerprints computed\nlocally, weak RSA flagged, options shown, disabled entries kept as comments.\nThe key you are currently connected with cannot be removed without an explicit\nconfirmation, writes are atomic, and a backup stays on the server.\n\n### Files on both sides\n\n![SFTP](docs/images/08-sftp.png)\n\nTwo panes, drag between them or in from Finder. Same SSH connection, same\nproxy. A dropped transfer resumes where it stopped.\n\n### Make it yours\n\n![Theme](docs/images/07-theme.png)\n\nThemes are plain JSON in `themes/` — keep them in git, trade them with people,\nimport `.itermcolors`, alacritty and base16. Palette, font, ligatures, line\nheight, background image, scanlines, glow, vignette, window opacity. Bind a\ntheme to a group so production is unmistakably red.\n\nAnd there is a cat in the corner. Or a sugar glider. It sleeps while the app is\nlocked, it never covers your output, and one switch turns it off forever.\n\n---\n\n## Give an agent your servers without giving it your keys\n\nPhosphor is also a **Model Context Protocol server**. Register one command and\nClaude Code, Claude Desktop, Cursor or any other MCP client can list your hosts,\nread metrics, inspect containers, follow logs and — when you allow it — run\ncommands, restart containers, manage `authorized_keys`, and add, change or\nremove hosts in your own list. Anything that edits the list asks you first, in\nevery mode.\n\nThe difference from handing a model a shell: **the app holds the connection, the\nagent holds nothing.**\n\n| | Shell tool with raw `ssh` | Credentials in an MCP config | Phosphor |\n|---|---|---|---|\n| Where the key lives | on disk, agent-readable | on disk, agent-readable | Keychain / Secure Enclave, behind Touch ID |\n| What is reachable | everything | everything | only hosts you enabled, in the mode you set |\n| `rm -rf /` | runs | runs | refused by a deny-list that overrides every mode |\n| Human in the loop | none | none | per-write confirmation, grants expire in 15 min |\n| Trail afterwards | shell history, maybe | none | an audit log with no writing tool |\n| Secrets in output | whatever is on screen | whatever is on screen | masked before the model sees them |\n| Runaway loop | unbounded | unbounded | rate-limited writes |\n\n```sh\nclaude mcp add phosphor /Applications/Phosphor.app/Contents/MacOS/phosphor-mcp\n```\n\nIn the MCP registry it is `io.github.Kirusshenkin/phosphor`; every release also\nships a `.mcpb` bundle with a published SHA-256 for clients that install that\nway.\n\nThirteen tools, seven of them read-only. Every host starts `disabled` — nothing is\nreachable until you choose `read-only`, `confirm` or `full` for it, and\nproduction servers are meant to stay `read-only`. A compromised server can put\nanything it likes into a log line the model reads; it still cannot grant itself\na mode, get past the deny-list, or erase the record of trying.\n\n**Full details: [`docs/MCP.md`](docs/MCP.md)** — tool catalogue, policy, audit,\nand the exact error the agent gets when the app is closed, locked or refusing.\n\n## Principles\n\n**No integrations.** The only network traffic the app makes is SSH to your own\nservers and the update feed. No telemetry, no accounts, no third-party\nservices, nothing phoning home.\n\n**Secrets stay secret.** Never in a log line, a crash report, an MCP audit\nentry or an error message. Terminal scrollback is not written to disk by\ndefault.\n\n**Errors tell you what to do.** \"Could not connect\" is a bug. \"The proxy at\n127.0.0.1:10808 is not answering — is V2Box running?\" is an error message. The\napp distinguishes a dead proxy from an unreachable server from a refused\ncredential, because otherwise diagnosis is guesswork.\n\n**It stays fast because it is open all day.** Bytes from the network are\nbatched into ~16 ms windows before they reach the emulator, the draw path\nallocates nothing, every buffer is bounded, polling stops when the window is\nnot visible, and animations only ever touch `transform` and `opacity`.\n\n**Strict Swift 6 concurrency**, in every target, with no escape hatches.\nNetwork, parsing and disk work live in actors; only view models are on the main\nactor.\n\n**Two languages.** English and Russian, both through a String Catalog. Not one\nhardcoded interface string — a linter checks.\n\n---\n\n## Status\n\nBuilds, runs, **179 tests green**. Eleven screens: lock, hosts, terminal with\npersistent sessions, files, Docker, monitor, keys, provisioning, AI activity and\nsettings. Interface in Russian and English.\n\nWhat works against a real server: SSH over one multiplexed connection per host,\ncontainer listing with actions and streaming logs, `/proc` metrics, reading and\nediting `authorized_keys`, provisioning recipes, both file panes, and an\ninteractive shell that rides the same socket.\n\nMCP works end to end: an `phosphor-mcp` shim ships inside the bundle, speaks\nJSON-RPC over stdio and proxies to a local socket the app owns. Every host\nstarts disabled, writes need a decision from a person, a deny-list overrides\nevery mode, and the audit log has no writing tool — the model can act but\ncannot erase its trail.\n\nHosts import from `~/.ssh/config`, from `known_hosts` and from a Termius vault,\nwhose plaintext dump is deleted once the hosts are inside the encrypted profile.\n\nWhat is not built yet: the native Citadel transport (the process-based one is\ntested and works), the pet in the corner, and in-app updates through Sparkle.\n\nIdle CPU is zero — no timers, polling pauses when the window is in the\nbackground.\n\n## Install\n\n```sh\ncurl -fsSL https://github.com/Kirusshenkin/terminalOs/releases/latest/download/Phosphor.zip -o Phosphor.zip\nunzip -q Phosphor.zip -d /Applications\nxattr -dr com.apple.quarantine /Applications/Phosphor.app\n```\n\nOr download `Phosphor.zip` from the release page and drag the app into\nApplications.\n\n**macOS will warn you the first time.** The app is ad-hoc signed — there is no\nApple Developer certificate behind it — so everything downloaded from the\ninternet lands in quarantine. This is not damage:\n\n1. Double-click the app, dismiss the warning.\n2. System Settings → Privacy & Security → scroll down → **Open Anyway**.\n3. Confirm. It never asks again.\n\nThe `xattr` command above does the same thing in one step.\n\nEvery release ships `SHA256SUMS.txt`; verify with\n`shasum -a 256 -c SHA256SUMS.txt`.\n\nThere is no in-app updater yet — check the releases page. The version you are\nrunning is in the About panel.\n\n### For AI agents\n\nEach release carries `latest.json`, so nothing has to be scraped:\n\n```sh\ncurl -fsSL https://github.com/Kirusshenkin/terminalOs/releases/latest/download/latest.json\n```\n\n```json\n{\n  \"version\": \"0.1.0\",\n  \"url\": \"https://github.com/.../Phosphor-0.1.0.zip\",\n  \"sha256\": \"…\",\n  \"mcp\": { \"command\": \"/Applications/Phosphor.app/Contents/MacOS/phosphor-mcp\",\n           \"transport\": \"stdio\" }\n}\n```\n\nThe bundle contains an MCP stdio shim. Register it and Phosphor exposes its\ntools:\n\n```json\n{\n  \"mcpServers\": {\n    \"phosphor\": {\n      \"command\": \"/Applications/Phosphor.app/Contents/MacOS/phosphor-mcp\"\n    }\n  }\n}\n```\n\nThe shim talks to the running app over a Unix socket in the user's home\ndirectory; it carries no credentials of its own. If the app is closed or locked\nit says so and every tool call fails closed — MCP access is off by default and\nhas to be granted in the app, per session, with a fingerprint.\n\n## Releasing\n\nTag and push:\n\n```sh\ngit tag v0.1.0 && git push origin v0.1.0\n```\n\n`.github/workflows/release.yml` runs the tests, then `.github/scripts/package.sh` —\nwhich is the same script used locally, so a release can always be reproduced on\nyour own machine:\n\n```sh\nMARKETING_VERSION=0.1.0 BUILD_NUMBER=1 ./.github/scripts/package.sh\n```\n\nIt produces `dist/Phosphor-<version>.zip`, a copy named `Phosphor.zip` (only an\nexact filename works behind `/releases/latest/download/`), `SHA256SUMS.txt` and\n`latest.json`. The workflow unzips the archive again and runs\n`codesign --verify` on it before publishing: a bundle whose signature does not\nsurvive the round trip will not open on anyone's machine.\n\n## Build\n\nRequires macOS 26+ and a Swift 6.3 toolchain.\n\n```sh\ngit clone https://github.com/Kirusshenkin/terminalOs.git\ncd terminalOs\nswift build\nswift test\n./.github/scripts/check.sh     # format, lint, build, tests — before every commit\n```\n\n## Layout\n\n```\nSources/          PhosphorCore, VaultKit, HostsKit, SSHKit, DockerKit,\n                  MetricsKit, KeysKit, ThemeKit, ProvisionKit, PhosphorUI\ndesign/           UI artboards (.dc.html), one per screen\ndocs/PLAN.md      The full architecture plan, in Russian\ndocs/images/      Screenshots rendered from the artboards\n```\n\n## Contributing\n\nThe plan comes first — requirements land in [`docs/PLAN.md`](docs/PLAN.md)\nbefore any code. Conventions worth knowing before a pull request: code, names\nand commit messages in English; user-visible strings in both English and Russian\nthrough `Strings`, never hardcoded; strict Swift 6 concurrency in every target;\nno swallowed errors, and every message says what happened *and* what to do; no\nsecrets in logs, errors or the audit; bounded buffers and nothing allocated in\nthe draw path.\n\n## Security\n\nPlease report vulnerabilities privately — see [`SECURITY.md`](SECURITY.md).\nThe threat model is `docs/PLAN.md` §15.\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 12903,
  "sha": "0e399915d1bbb75eddb1e7e9297f8d2fa758658d5a93f8d0aea7fad3bb0e3708",
  "repo_slug": "kirusshenkin/terminalos",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_kirusshenkin_phosphor_03321258/readme"
}