Docs

Glyph is one zsh file. It names your terminal session at launch, then gets out of the way. Everything it can do is on this page.

Getting started

zsh, and at least one agent CLI on your PATH. Nothing else.

$git clone https://github.com/fru-dev3/glyph.git
cd glyph && source ./install.sh

The installer copies one file to ~/.config/glyph/glyph.zsh and adds one source line to ~/.zshrc. Re-running it is safe.

Why source, not ./install.sh

Run as a path it is a child process, and a child cannot define functions in the shell that started it, so glyph would not exist until you reloaded. Sourcing installs and loads in one step. Already ran it the other way? . ~/.config/glyph/glyph.zsh catches you up without opening a new shell.

Check it without launching anything

$glyph version
glyph agents
GLYPH_DRYRUN=1 claude billing

GLYPH_DRYRUN=1 prints the exact argv Glyph would run and stops there. Nothing starts, nothing is recorded.

Then launch for real

$claude billing
billing·acme-api·claude-code·mbp·2026-09-12·0556

That string is the session name. On Claude Code it is the real session name and rides Remote Control to the web app and your phone. On every other agent it lands on the terminal title, the tmux window, and glyph ls.

How a name is built

Six tokens joined by ·, all lowercase, hyphens inside words.

TokenComes fromExample
Labelthe one bare word you typedbilling
Projectthe git repo directory you launched fromacme-api
Agentwhich wrapper ranclaude-code
Machinescutil --get ComputerName on macOS, hostname elsewherembp
Datelaunch date2026-09-12
Timelaunch time0556

The rule for arguments

One bare word is a label. Anything with a space is a prompt.

$claude # project only
claude billing # labelled
claude billing "fix the retry" # labelled, with a prompt
claude "fix the retry" # a phrase is a prompt, so no label

Flags like -p and subcommands like claude mcp or codex resume pass through untouched, so scripts and CI behave exactly as before.

Machine tags

Normalised to lowercase hyphenated form. Rivers MacBook Pro becomes rivers-macbook-pro, DESKTOP-8KQ2LM1 becomes desktop-8kq2lm1. Glyph never guesses a model or an OS release. If yours reads badly, set it:

$export GLYPH_MACHINE=laptop

Project overrides

One tab-separated line per directory in ~/.config/glyph/names.tsv. Overrides are normalised the same way.

$fd-apps-memosa memosa
acme_api_v2 acme-api

Preview any name

$glyph name
glyph name billing

Launching agents

Keep typing the command you already type. Glyph only adds the name.

Claude Code

The one agent that can name its own session, so the name becomes the real session name and reaches Remote Control.

$claude billing
# runs: claude -n 'billing·acme-api·claude-code·mbp·2026-09-12·0556' --remote-control

Turn Remote Control off with GLYPH_RC=0.

Everyone else

No agent but Claude has a session-name flag, so the name goes on the terminal title, the tmux window and the registry instead.

$codex audit
agy migration
cursor-agent pair

Agents may overwrite the terminal title after launch. Fleet keeps its own pane-border labels, which they cannot touch.

See what you have running

$glyph ls
glyph ls 50

Sessions already open

Glyph names a session from argv, so a session you started without it never got a name. glyph mark applies everything Glyph can still reach from outside the agent, and prints the one line only the agent itself can run.

$glyph mark hotfix
hotfix·acme-api·claude-code·mbp·2026-09-12·2107
  set the terminal title
  renamed the Herdr pane
  recorded it in glyph ls

this Claude session is still called 'fru-3e'

an agent can only rename itself. paste this into it:
  /rename hotfix·acme-api·claude-code·mbp·2026-09-12·2107
  /remote-control

It reports only the surfaces it actually reached. No terminal, no tmux, no Herdr, or GLYPH_TITLE=0 and the matching line is simply absent.

Let it type the commands for you

Add --send and Glyph types the /rename into the pane itself, over herdr pane send-text or tmux send-keys, following it with /remote-control when the bridge is off.

$glyph mark hotfix --send

It refuses outside an agent session, where the keystrokes would land in your shell instead. If the agent is mid-answer the text queues until it is ready.

Inside Herdr

Herdr sets no TMUX, so the tmux path never applies there. Glyph renames the Herdr pane instead, through herdr pane rename. That label belongs to Herdr, which is the point: an agent cannot overwrite it with its own terminal title, and Codex and AGY both do exactly that a second after they start.

This applies to normal launches too, not just glyph mark. In plain tmux Glyph now also turns off allow-rename and automatic-rename on the window, for the same reason.

What it cannot do

SurfaceAfter launch
Terminal titleYes. Written straight to /dev/tty, so it never lands in a pipe.
tmux window and pane labelYes.
glyph ls registryYes, recorded as a mark row.
The agent's own session nameOnly from inside it. Glyph prints the /rename line to paste.
Remote Control bridgeNot from outside, but Claude Code can switch it on from inside with /remote-control. Glyph reads bridgeSessionId and offers that line only when the bridge is actually off.

Inside Claude Code it detects the agent from CLAUDECODE and reads the live session name out of ~/.claude/sessions/<pid>.json, so you can see what the session is called before you change it. For any other agent, name it yourself:

$glyph mark audit codex

What is running

glyph ls is a log of launches Glyph performed. glyph ps is the other question: what is alive right now, including sessions Glyph never started.

$glyph ps
AGENT   NAME                                 NAMED  RC   PID
claude  billing·acme-api·claude-code·mbp  glyph  on   60129
claude  fru-3c                            auto   off  96624

11 live, 10 without a glyph name or without Remote Control

NAMED is glyph when the name has Glyph's shape, user when someone set it by hand, auto when the agent derived it. RC is whether Remote Control is on, so you can see at a glance which sessions your phone cannot reach.

Reads the live session files and checks each pid, so it lists only what is actually running. Claude Code today: the other agents do not publish a session registry.

Usage and quota

How much is left, and when it comes back, across agents.

$glyph usage
codex  plus  5h      ████████████████   98%  resets in 10m
codex  plus  weekly  █████░░░░░░░░░░░   31%  resets in 5d 20h
claude -     5h/wk   quota is server side, add --live
agy    not exposed

Each agent is a different story, and Glyph says which is which rather than blending them:

AgentQuota and resetToken counts
CodexExact and offline. Every rollout carries a rate_limits record with the window, percent used and reset time, so both the 5h and weekly windows come straight off disk.Yes
Claude CodeNot on disk. Window boundaries are decided server side, so --live asks Anthropic directly, authorised from the Keychain.Yes, from the transcripts
AGYNot exposed. No usage flag on the CLI, no token fields in its transcripts.No

Detail for one agent

$glyph usage claude
glyph usage codex
glyph usage --live
glyph usage --json
Token counts are not billing

They are what your own transcripts recorded, which is useful for seeing where the volume went, but it is not the number your plan is measured against. For that, use --live.

Reading a large transcript history takes a few seconds, so the result is cached for ten minutes. --refresh rescans now, GLYPH_USAGE_TTL changes the window. --live is the only part of Glyph that makes a network request; the token is passed to curl over stdin so it never appears in ps.

Auto-approve

Every agent has a flag meaning "stop asking me to approve each tool call", and they all spell it differently. GLYPH_YOLO=1 sends whichever one is right for the agent you are launching.

$GLYPH_YOLO=1 codex audit
# runs: codex --dangerously-bypass-approvals-and-sandbox
Separate from naming

Naming always happens. Auto-approve never happens unless you ask for it.

Make it the default

Setting it per command gets old. Export it once and every agent you launch through Glyph gets its own auto-approve flag, with nothing to remember:

$echo 'export GLYPH_YOLO=1' >> ~/.zshrc
exec zsh

Be clear about what that means: every agent will run every tool call without asking you first, in every project, until you unset it. That is the point of the flag, and it is why Glyph will not turn it on for you.

Check what any agent would actually get, without launching it:

$GLYPH_DRYRUN=1 codex audit

Agents

A wrapper is defined only for agents actually on your PATH. Run glyph agents to see yours.

AgentCommandCarries the name asGLYPH_YOLO=1 sends
Claude Codeclaudereal session name--dangerously-skip-permissions
Codexcodextitle--dangerously-bypass-approvals-and-sandbox
AGYagytitle--dangerously-skip-permissions
Cursorcursor-agenttitle--force
Crushcrushtitle--yolo
Snowflake Cortexcortextitle--dangerously-allow-all-tool-calls
Hermeshermestitle--yolo
omniomnititlenone
OpenCodeopencodetitle--dangerously-skip-permissions
pipireal session namenone

Add your own

Any CLI, without waiting for a release. One tab-separated line per agent in ~/.config/glyph/agents.tsv: command, auto-approve flag, label. Leave the flag empty if it has none.

$openclaw --yolo OpenClaw
grok --force Grok

These merge over the built-ins, so you can also correct a flag Glyph gets wrong.

Fleet

One preset launches several agents at once, each in its own marked pane. Fleet is the only part of Glyph that opens anything.

$glyph fleet init
glyph presets
glyph fleet review

The presets fleet init writes

It only adds what is missing, so it never touches presets you already wrote. Replace studio with one of your own machines.

PresetSlotsWhat it is for
soloclaudeone agent, named. the everyday case
reviewclaude codextwo vendors on the same diff, for a second opinion
duoclaude agyAnthropic and Google side by side
ciclaude agy codexthe three-up bench
benchclaude codex agy cursor-agenteverything local, one pane each
pairclaude cursor-agenta terminal agent beside an editor-native one
deepclaude cortexa coding agent next to a warehouse-native one
lightcrush opencodelightweight runners for cheap, quick passes
splitclaude codex:studioone local, one on a remote box
spreadclaude claude:studiothe same agent on two machines
cloudclaude:studio codex:studioboth agents on the remote box

Without a preset

Name the agents directly and Fleet runs them as an ad-hoc group.

$glyph fleet claude codex
glyph fleet claude agy codex:studio

Preview before opening panes

$GLYPH_DRYRUN=1 glyph fleet ci

Prints the backend, the session, and one line per pane. Opens nothing.

Presets live in ~/.config/glyph/fleet.conf as name = slot slot slot. Edit it by hand any time.

Moving between panes

On the tmux backend a Fleet is one session, one window, and one tiled pane per slot. Glyph leaves you in the first pane and turns the mouse on for that session, so a click moves between them. Each pane border carries its index and its label.

MoveKeys
Click a paneMouse, on by default for the Fleet session only
Next panectrl-b o
By directionctrl-b then an arrow key
By numberctrl-b q, then the digit shown
Zoom one panectrl-b z, again to unzoom

Set GLYPH_FLEET_MOUSE=0 to leave the mouse alone. Glyph only ever sets it on the Fleet session, never on your global tmux config.

Remote agents

A slot is <agent> or <agent>:<machine>. For a remote slot Glyph opens SSH in that pane, changes to the same working directory, and launches the agent through the remote Glyph wrapper, so it gets that agent's own flags and its own name.

$glyph hosts
glyph fleet split
GLYPH_DRYRUN=1 glyph fleet cloud

How a machine name resolves

First hit wins.

OrderSourceExample
1An entry in ~/.ssh/configHost mini
2A name in ~/.ssh/known_hosts, so the pane never stalls on a fingerprint promptmac-mini
3Tailscale, where a short name expands to its MagicDNS namemini → mini.tailnet.ts.net
4Anything else, passed to SSH untoucheduser@10.0.0.5
Accept the host key once

Run ssh <host> by hand the first time. After that, remote panes start clean.

Tailscale is optional and detected automatically; nothing changes if you do not use it. Remote slots work on every backend, because they all build the same SSH command.

Workspace backends

Backends decide where Fleet opens panes. They change nothing about launching a single agent.

BackendWhat it does
autoHerdr, then cmux, then Zellij, then WezTerm, then tmux.
herdrOne Herdr tab per slot, each running in the tab's own pane. Glyph also ships a Herdr plugin that puts agent quota in a pane: herdr plugin install fru-dev3/glyph/herdr-plugin
cmuxOne cmux workspace per slot.
zellijOne named Zellij pane per slot.
weztermOne WezTerm tab per slot.
tmuxTiled panes in a new tmux session.
$GLYPH_FLEET_BACKEND=herdr glyph fleet ci

Glyph is not tied to any one workspace tool. With none running, Fleet falls back to tmux.

Command reference

CommandWhat it does
glyph name [label]Print the session name this directory would produce. Nothing is launched.
glyph psEvery agent session alive right now, named or not, with Remote Control state.
glyph usage [agent]Quota and token counts across agents. --live, --json, --refresh.
glyph doctorCheck the install and report what is wrong. Non-zero exit when something needs attention.
glyph mark [label] [agent] --sendAs below, but types the /rename into the agent instead of printing it.
glyph mark [label] [agent]Name a session that is already open: terminal title, tmux, registry, and the /rename line to paste.
glyph ls [n]The last n recorded sessions (default 20): time, agent, name, machine.
glyph agentsEvery agent found on your PATH, its label, and its auto-approve flag.
glyph hostsMachines you can put after a colon in a Fleet slot: SSH config entries, then tailnet peers.
glyph presetsThe Fleet presets currently defined.
glyph fleet initWrite the example presets, keeping any you already have. Safe to re-run.
glyph fleet <preset>Launch a preset, one marked pane per slot.
glyph fleet <agent> [<agent>...]Launch an ad-hoc fleet without defining a preset first.
glyph updateFetch the latest glyph.zsh from GitHub.
glyph versionThe installed version.

Configuration

Behaviour

VariableDefaultEffect
GLYPH_YOLO=1offSend each agent's auto-approve flag.
GLYPH_DRYRUN=1offPrint the argv that would run. Launch nothing, record nothing.
GLYPH_OFF=1offKeep the label and project, drop the machine and time.
GLYPH_SEP·Separator between tokens.
GLYPH_FMT%Y-%m-%d·%H%Mdate(1) format for the stamp.
GLYPH_MACHINEcomputer nameMachine tag, when the hostname does not read well.
GLYPH_RC=0onDo not add Claude's --remote-control.
GLYPH_TITLE=0onLeave the terminal and tmux titles alone.
GLYPH_LOG=0onDo not record sessions locally.
GLYPH_FLEET_MOUSE=0onDo not turn the mouse on for the Fleet tmux session.
GLYPH_FLEET_BACKENDautoauto, herdr, cmux, zellij, wezterm or tmux.

Paths

VariableDefaultPoints at
GLYPH_USAGE_TTL600Seconds to cache the transcript scan behind glyph usage.
GLYPH_CLAUDE_APIapi.anthropic.comHost glyph usage --live asks for quota.
GLYPH_FLEET_CONF~/.config/glyph/fleet.confFleet presets.
GLYPH_AGENTS~/.config/glyph/agents.tsvExtra agents you define.
GLYPH_MAP~/.config/glyph/names.tsvProject name overrides.
GLYPH_STATE~/.local/state/glyphSession registry (honours XDG_STATE_HOME).
GLYPH_UPDATE_URLGitHub raw glyph.zshWhere glyph update pulls from. Point it at a fork.
GLYPH_SSH_CONFIG~/.ssh/configWhere host resolution reads SSH hosts.
GLYPH_KNOWN_HOSTS~/.ssh/known_hostsWhere host resolution reads trusted hosts.
GLYPH_TAILSCALEauto-detectedPath to the tailscale binary.

Files on disk

PathWhat it is
~/.config/glyph/glyph.zshThe wrapper itself. Replaced by glyph update; a symlink here is followed, not overwritten.
~/.config/glyph/fleet.confFleet presets, one name = slots per line.
~/.config/glyph/agents.tsvExtra agents: command, auto-approve flag, label, tab separated.
~/.config/glyph/names.tsvProject overrides: directory name, display name, tab separated.
~/.local/state/glyph/sessions.tsvWhat glyph ls reads. Delete it any time.
~/.zshrcOne source line, added by the installer.

Updating

$glyph update
glyph version
  • Loads the new file into the shell you ran it in, so there is nothing to reload.
  • Refuses to install a file that does not parse.
  • Keeps the previous copy at ~/.config/glyph/glyph.zsh.bak.
  • Follows a symlink and writes the file it points at, so an install linked into a synced folder keeps its link.
  • Never touches fleet.conf, names.tsv or agents.tsv.
  • Point GLYPH_UPDATE_URL somewhere else to track a fork.

Other shells you already had open keep the old wrapper until you run exec zsh in them.

Doctor

Before troubleshooting by hand, ask Glyph what it thinks is wrong.

$glyph doctor

It checks the wrapper path and whether it is a symlink, version drift between the file on disk and the copy loaded in this shell, the ~/.zshrc line, which agents are on your PATH but not actually wrapped, the Fleet backend it would use, the registry, and your config files. It exits non-zero when something needs attention, so it works in a script.

The check that catches most confusion is version drift: an updated file on disk and an older copy still loaded in the shell you are typing in.

Troubleshooting

SymptomFix
command not found: glyph right after installingThe installer ran as a child process and could not touch your shell. Run . ~/.config/glyph/glyph.zsh, or use source ./install.sh next time.
agy billing reports an unexpected argumentAn older wrapper is still loaded in that shell. Run exec zsh.
A Fleet pane stalls on a host key fingerprintAccept the key by hand once with ssh <host>, then the pane starts clean.
glyph fleet opens a nested tmux inside HerdrSet GLYPH_FLEET_BACKEND=herdr, or run Fleet outside Herdr.
Claude's startup banner does not show the nameIt never does. Read ~/.claude/sessions/<pid>.json, or look at the session list on the web or your phone.
The machine tag reads badlySet it yourself: export GLYPH_MACHINE=laptop.
Nothing happens at allConfirm the source line is in ~/.zshrc, then run glyph version. If that fails, re-run ./install.sh.

Two things that cost real debugging time

  • Claude's --remote-control <name> does not name the session. It opens the bridge, and the session still comes back as nameSource: "derived". Only -n sets the name, so Glyph passes both.
  • In zsh, argv is $@. Declaring local -a argv in a function silently empties the positional parameters. Worth knowing if you fork this.

Uninstall

$# remove the glyph source line from ~/.zshrc
rm -rf ~/.config/glyph
rm -rf ~/.local/state/glyph # optional: the session registry
exec zsh

Nothing else was installed and no agent config was modified, so that is the whole of it.