Skip to content
fHpro0Public

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

hefyn

A native macOS terminal, written in pure Rust, that AI agents can work in without seeing your secrets.

Status: work in progress Rust 1.90+ macOS GPUI License

hefyn with the session tree, command blocks and a split screen

Warning

Work in progress. hefyn is under active development and only early pre-releases exist. Things break, and settings and the MCP API can change without notice.

Install

Download hefyn-<version>-macos-universal.dmg from Releases, open it and drag hefyn to Applications. The build is universal (Apple silicon and Intel) and needs macOS 13 or newer.

Pre-releases are not notarized yet, so Gatekeeper refuses the first launch. Right-click hefyn.app and choose Open, or run xattr -dr com.apple.quarantine /Applications/hefyn.app.

Or build from source (see Getting started):

cargo run -p hefyn-app --release

Verify a downloaded dmg against the .sha256 file next to it:

shasum -a 256 -c hefyn-<version>-macos-universal.dmg.sha256

hefyn is a GPU-rendered terminal built on GPUI and alacritty_terminal. It organizes many shells and SSH connections in a session tree and has a built-in MCP gateway. An agent such as Claude Code can list sessions, read output, run commands and edit files in the sessions you allow, and everything it gets back has been redacted first. Sensitive values reach the agent as variable names it can pass back, never as the values themselves.

Highlights

A real terminal

Alacritty grid, truecolor, IME input, mouse reporting, selection, scrollback, bracketed paste and OSC 52. Links open with ⌘-click. Native window with the traffic lights in hefyn's own top row; no web view anywhere.

Command blocks

Shell integration for zsh, bash and fish groups every command with its output, with a context line showing the directory, git branch and changed files. Your dotfiles are never modified.

Session tree

Groups, screens and sessions with icons, emoji and accent colors. Sort them with drag and drop or A→Z and navigate with the keyboard. The tree and your open tabs come back on every launch.

Panes and screens

Split side by side (⌘D) or top and bottom, then zoom, resize and cycle panes. Split sessions become a screen in the tree, so the layout comes back exactly as you left it.

SSH connections

Hosts from ~/.ssh/config as quick picks, jump hosts, reconnect, and command blocks on the server without installing anything there (⌘⇧K).

MCP gateway

Opt-in per session or group. Each connection has its own key, access level, rate limit, command rules and folder lock. Risky commands wait for your approval.

Secrets stay secret

Everything an agent reads is redacted by regex rules, an entropy detector and a local GLiNER model. If a detector fails, nothing is sent.

Variables, not values

A detected value reaches the agent as {{var:EMAIL_1}}. The agent passes the name back in commands and file edits and hefyn puts the real value in. Keychain secrets work the same way with {{secret:NAME}}.

File edits you can see

read_file and edit_file let agents change code with exact replacements, written directly and atomically. Every edit appears in the session as a card with a diff: ✎ Edited src/limit.rs +3 −1.

Undo and history

Before an agent changes anything, hefyn snapshots the working directory. Revert… on any agent block or edit restores it; the agent history (⌘⇧H) lists every call.

Make it yours

JSON themes and settings reload while the app runs. Custom SVG icons, an editable keymap with a searchable cheat sheet (⌘/) and a command palette (⌘⇧P).

Pure Rust

One native binary, GPU-rendered with GPUI. The redaction model runs in-process; nothing leaves your machine unless you connect an agent.

Screenshots

An agent working in a session: its command block, the redacted output it received, and an edit card with a diff
An agent's commands and edits run in a visible terminal. You see the real output; the agent gets {{var:…}} names instead of sensitive values.

Command blocks with the git context line, durations and exit status hefyn Dark with the sidebar collapsed to a rail and an agent's file edits with diffs
Left: command blocks with the git context, duration and exit status. Right: hefyn Dark with the sidebar collapsed to a rail and an agent's edits as diff cards.

Getting started

cargo run -p hefyn-app --release          # run hefyn
scripts/bundle-macos.sh --release         # build target/bundle/hefyn.app

Requires Rust 1.90+ on macOS. bundle-macos.sh also needs rsvg-convert and iconutil.

bundle-macos.sh also takes --universal (arm64 + x86_64), --dmg and --notarize. Without MACOS_SIGN_IDENTITY the bundle is ad-hoc signed.

The config dir is ~/Library/Application Support/dev.hefyn.hefyn. Set HEFYN_CONFIG_DIR to use a different one. See keyboard shortcuts and themes and appearance.

SSH connections

  1. Choose New SSH connection… (⇧⌘K, the server button in the sidebar header, the command palette, or a group's context menu). Hosts from your ~/.ssh/config are offered as quick picks; you can also paste user@host:port, an ssh:// address or a whole ssh -p 2222 host command into Host and the other fields fill in. Key file, jump host, start directory and a custom name are there too.
  2. Press Connect. The connection is a normal session (server icon, a green dot while it is up) whose tab shows user@host:~/dir. Splitting it opens another connection to the same server in the same directory. When the connection closes, the pane offers Reconnect; Edit connection… in the session's context menu changes the target.
  3. Let an agent work on this server (in the same dialog, off by default) shares the new session with an agent at the access level you pick and shows the one-line setup. The agent's commands run on the server through that connection; risky ones still ask for your approval and output is redacted before the agent sees it.

Command blocks, exit codes and the current directory work on the server for bash and zsh: hefyn brings its shell integration along for this session only and writes nothing to the server (switch it off per connection under Advanced, or by default in Settings → Terminal → SSH). The same integration applies when you type ssh host in an ordinary session.

Connecting an agent

  1. Right-click a session or group and choose Agents → Share with agent… (also the shield button in the sidebar header, or Share session with agent… in the command palette).
  2. Pick what the agent may do (Read-only looks around and runs read-only commands like ls, cat, grep; Read & write also edits files and runs commands, asking you before anything risky) and click Create connection. The agent stays inside the session's folder and everything below it, never above.
  3. Click Copy setup command and paste it into your shell. The dialog shows "Waiting for the agent to connect…" and flips to "Connected" on its first request:
claude mcp add --scope user --transport http hefyn-<name> http://127.0.0.1:47800/mcp/<binding-id> \
  --header "Authorization: Bearer <key>"

Other MCP clients can use Copy JSON. Settings → Agents lists every connection with its status ("Active", "Used 5 min ago", "Not used yet"), lets you rename it, switch it off, change what it reaches, copy or rotate its key, and edit the access levels.

Security model: what happens on every agent request
  1. Transport checks. The gateway binds only to loopback and rejects foreign Host/Origin headers, which protects against DNS rebinding. An unknown, disabled or wrong-token binding gets the same 401.
  2. Scope. A binding governs one session or one group. The most specific enabled binding wins, so every session is governed by at most one endpoint. Sessions outside the scope are reported as unknown.
  3. Policy. The policy is re-read on every call, so edits apply immediately. It covers:
    • capabilities: list, read, run, write files, send input;
    • a per-binding rate limit;
    • command rules for run_command:
      • newlines, shell operators (; & | $ > < ( ) `) and privilege escalation (sudo, su, doas, …) are rejected;
      • deny globs always win, and they match case-insensitively;
      • the default deny list covers secret files for every reader (.ssh, .aws, .netrc, …) and flags that turn read-only tools into command runners (find -exec, rg --pre, --output);
      • project .env files are an ask rule instead: reading one needs your approval, and the output is still redacted. The list_env_keys tool returns only the variable names in an env file (inside the folder lock) and needs no approval.
      • Folder lock on SSH sessions. The folder is the connection's Start directory (or the first folder the server shell reports). Paths are checked lexically (.., sibling folders such as wp-content-old, ~ are refused) and, through hefyn's remote shell integration, again on the server with symbolic links resolved. Programs whose files cannot be known from their arguments (php, python, wp, bash, ...) need your approval; Read-only never runs them. Without command blocks (integration) on the connection the lock refuses to run anything. write_file and edit_file write text files inside the folder (never git hooks). In local sessions hefyn writes the file itself, atomically, after the same checks and with symbolic links refused; over SSH the content is typed through the connection.
  4. Redaction, failing closed. All text returned to the agent is redacted. If any detector errors, the call fails and no text is sent. Output is redacted in whole lines with context before the cursor, and a still-incomplete trailing line is held back, so a secret is never split across two reads.
  5. Guards (optional). laya checks commands and output. If a guard is enabled but unavailable, commands are denied and output is withheld.
  6. Audit. Every call is logged with its outcome. Commands are logged in redacted form, and raw output is never logged.

send_input gives full control, because typed text can run anything. It is off by default, and the UI warns before you turn it on.

Variables and secrets

Agents never see sensitive values, but they can still use them.

  • Detected values. When output contains something a detector flags (an email address, a name, an API key, a high-entropy token, …), the agent sees a placeholder such as {{var:EMAIL_1}} or {{var:API_KEY_1}} instead. The same value keeps the same name for the whole session, and the values live only in memory until hefyn quits.
  • Using them. The agent passes the placeholder verbatim in run_command, write_file or edit_file, and hefyn substitutes the real value at the last moment (as one quoted word in commands, as plain text in files). Output that echoes it is redacted again.
  • When hefyn asks you. Putting a value back into the file it came from is free, so an agent can read a file with secrets, edit it and write it back without destroying them. Using a value anywhere new (another file, a command) asks you once per variable and session.
  • Your own variables. set_variable stores a named value per session; capture_redaction gives a detected value a friendlier name.
  • Keychain secrets. Secrets you add under Settings → Secrets are used as {{secret:NAME}} by connections you granted them to. They are never written into files, except back into a file that already contains them.

Agent tools

Tool What it does
list_sessions Sessions the connection may see, with folder and access level.
read_screen, read_output The visible screen or the output history, redacted.
run_command Runs one command line in the session (rules, folder lock, approval, snapshot).
read_file A file with line numbers, redacted. Same rules as cat on that path.
edit_file Exact search-and-replace edits, applied all-or-nothing, shown in the session as a diff.
write_file Creates, overwrites or appends a text file inside the folder lock.
list_env_keys The variable names in a .env file, never the values.
list_secrets, request_secret Keychain secrets granted to the connection; ask you for a new one.
set_variable, capture_redaction, list_variables, delete_variable Session variables.
send_input Types keys into the session. Off by default; it gives full control.

Redaction models

  • GLiNER (default feature gliner) runs in-process via gline-rs. Place tokenizer.json and onnx/model.onnx from e.g. knowledgator/gliner-pii-edge-v1.0 in <config dir>/models/gliner. Models are never bundled.
  • laya (feature laya) talks to a local laya-serve (pip install "laya[serve]"), configured via laya_url in settings.json.

Releasing

For maintainers. Pushing a v* tag runs .github/workflows/release.yml, which builds a universal dmg, signs it, notarizes it and attaches it to a GitHub Release together with its SHA-256.

git tag v0.1.0 && git push --tags

Repository secrets (Settings, Secrets and variables, Actions):

Secret Value
MACOS_CERTIFICATE_P12_BASE64 Developer ID Application certificate with private key, exported as .p12, base64-encoded (base64 -i cert.p12 | pbcopy).
MACOS_CERTIFICATE_PASSWORD Password chosen when exporting the .p12.
MACOS_SIGN_IDENTITY Full identity, e.g. Developer ID Application: Name (TEAMID).
APPLE_ID Apple ID used for notarization.
APPLE_TEAM_ID 10-character team ID.
APPLE_APP_PASSWORD App-specific password from appleid.apple.com.

If any of them is missing, the workflow still builds an ad-hoc signed, non-notarized dmg and marks the release as a pre-release. The tag version must match version in Cargo.toml, since the dmg name and CFBundleShortVersionString come from there.

Locally: MACOS_SIGN_IDENTITY="..." NOTARY_KEYCHAIN_PROFILE=hefyn scripts/bundle-macos.sh --release --universal --dmg --notarize (create the profile once with xcrun notarytool store-credentials hefyn).

Development

cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings

End-to-end UI tests use a port of gpui-agent in third_party/gpui-agent. It runs in offline scripted mode only, so nothing leaves the machine:

scripts/ui-test.sh tests/ui/new-session.json tests/ui/new-session-script.json

The script builds with a patched gpui-pre that exposes the accessibility tree. The patch is applied via --config for that build only, and Cargo.lock is restored afterwards. Tests run against a throwaway config directory.

Workspace layout
Crate Purpose
hefyn-app The hefyn binary: window, sidebar, tabs, panes, palette, settings.
hefyn-core Session tree, ids, icons, layouts, atomic JSON persistence. No UI dependencies.
hefyn-term PTY (portable-pty) + alacritty_terminal grid, shell integration, xterm key encoding.
hefyn-terminal-view GPUI terminal element and view: rendering, blocks, input, mouse, selection.
hefyn-policy MCP bindings, scopes, capabilities, command rules, tokens.
hefyn-redact Redaction pipeline (regex, entropy, GLiNER) and the laya Guard.
hefyn-mcp Streamable-HTTP MCP server (rmcp) enforcing policy and redaction.
hefyn-vault Keychain-backed secrets that agents can use but never read.
hefyn-undo Working-directory snapshots and restore for agent commands.
hefyn-extension Extension API (internal for now; see the roadmap).

Roadmap

hefyn is focused on being a great terminal first. Coming later:

  • Extensions: palette snippets, input rules, status items and custom redaction patterns via a declarative extension.json.

License

Apache-2.0. See NOTICE for attributions: the terminal rendering, key encoding and shell integration are adapted from tty7 (Apache-2.0), and third_party/gpui-agent is MIT.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages