Developer tools
The ? prompt
Type ? and a question at your zsh prompt and Io answers in a card under it, with a row of actions, follow-ups with ??, modes, your IO.md notes and, in a session, your Roles. What each part does, what is sent and what is released.
At your prompt, type ? and a question. Io answers in a card under it. The line is never run by
the shell and never lands in your history, so a question is as cheap as a keystroke, and a line
such as ?.txt still runs as it always did.
? why did cargo build fail
?? and how do I fix it # a follow-up: the last question and answer come along$ ? cargo build says it cannot find Cargo.toml╭─ ◆ Io ─────────────────────── Claude Code (local) · haiku · manual mode · 1.2s││ cargo could not find Cargo.toml here. The project is one folder down, in│ my-shop/.││ Change into it and build again:││ ❯ cd my-shop && cargo build││ Run · Copy · Follow up · Explain · Add folder ↓ to choose╰─ ?? follows up.
Where each part stands
Everything on this page is in the release (0.1.0-alpha.39), except the chat box in the panel,
which is only in iohr-preview, the next build.
| Part | Build |
|---|---|
? and ??, the card, every action under it, the questions Io asks back, the permission card, modes, folders Io may read and attached output | The release |
IO.md notes, your site as sources, --role, Roles answering in a session, bare iohr with its panel, and the asks count in your prompt | The release |
| The chat box at the bottom of the panel (below) | iohr-preview |
Turn it on
? is a hook for zsh. Add this to ~/.zshrc:
eval "$(iohr shell hook zsh)"To try the preview, use eval "$(iohr-preview shell hook zsh)" instead: the prompt then asks
iohr-preview. Only zsh has the hook today; iohr shell hook bash and iohr shell hook fish
print an error and exit 1. INORBIT_ASK=0 turns it off for one session. Inside the InOrbit app
the hook asks the app to draw the answer instead of printing it.
The hook also puts a count such as "3 asks" in your right prompt when asks wait for you. It reads
a number kept on disk and refreshes it in the background, so the prompt never waits for the
network. INORBIT_ASKS_PROMPT=0 turns it off, and iohr asks list shows them
(command line).
What the card is
Io answers by running Claude Code on your machine, under your own sign-in; it never uses an API key. The card says so. Its header is Io, with the agent, the model, the mode and how long it took on the right; a failed run shows a no answer badge. Without colour or a terminal, one plain line says the same: Io running on Claude Code, an AI model, under your own subscription.
A line under the header says what was read: "output not sent" when no command output went with the question, and "context: IO.md x3" when IO.md notes went with it. An AI answer can be wrong, so read a command before you run it. When Io needs to know something to answer, the card asks you, at most two questions, and answers again.
The actions under the card
If the answer holds a command, it is shown on its own line. Under the card, a row lists what you can do with the answer, and a key chooses:
| Action | What it does |
|---|---|
| Run | Runs the command at once, as a line you typed |
| Copy | Puts the command on the clipboard |
| Follow up | Starts a ?? question about this answer |
| Explain | Asks what the answer means, as a ?? question |
| Open | Opens the link or file the answer named. It refuses a program and a path outside the folder |
| Undo | Removes a permission rule this answer saved |
| Add folder | Keeps one more folder for Io to read on every later question (below) |
| Allow | Shown when Io asked to read a folder: allows it, then puts the question on your prompt again |
| Next steps | Numbered entries Io suggests, at most four: Read X/, Read X/ (all) for its subfolders too, Search for X and Run X. Each is asked as a ?? question when you pick it |
| Attach output | After a failed command and a question such as "why did that fail": re-runs the command or takes pasted output (below) |
| Asks | Shown when asks wait for you |
Run and Copy are there only when the answer has a command, and Open only when it names a link or a file. Run follows your rules before anything runs:
- A command a deny rule matches never runs.
- A command that deserves a second look (
sudo,rm -rf, a download piped into a shell, a forced git change) or one iohr cannot check (a substitution, a redirect) asks "Run it?" first, starting on No, unless an allow rule covers it. - A command with a placeholder in it (
path/to/...,<file>,YOUR_KEY, or a folder that does not exist) gets Copy only, so you fill it in yourself.
The key is the Down arrow on an empty line by default; [ask] menu_key in config.toml sets
ctrl-g, alt-enter or off. Without a key, iohr ask --menu opens the same menu.
When Io wants to run a command
Io reads with read-only tools. Before it runs a command that your rules do not cover, it asks you
on an Io card marked AI request: [1] Allow once, [2] Always in this project and
[3] No, starting on No. Arrows and Enter, a number, or y, a and n choose; Esc, q and
Ctrl-C mean no. Always saves the narrowest rule that fits, such as Bash(ls:*), in the project's
.inorbit/permissions.toml. Without colour, without a terminal or in a window under 40 columns,
the ask is one plain line: y once, a always in this project, n no.
iohr permissions list, allow, deny and remove show and change the rules, for the project or
for you, and iohr permissions check Bash ls says what they decide for one call.
Folders Io may read
Io reads the folder you ask from. Asked from your home folder, the card first asks whether to
trust it: yes and remember, this time only, or no. The answer is kept in trusted.toml, and
folders that hold secrets stay closed either way.
When a question needs another folder (your home folder, the root, or one the question names), Io asks to read it instead of saying it cannot. Allow keeps that yes for the folder, and it is used only when a question needs that folder again. To name more folders yourself:
? what does the deploy script expect --read ../infra| Way | Scope |
|---|---|
--read FOLDER (or --add-dir), repeated | One question |
IOHR_ASK_READ | Every question in this shell: a list of paths, : apart (; on Windows) |
[ask] read in config.toml | Every question |
| Add folder in the menu | Every later question, kept in trusted.toml |
At most 8 folders. Each must exist and be readable. iohr refuses the root, your home folder (only
an explicit --read ~ names it) and every folder above it. Secret places stay closed whatever you
allow: ~/.ssh, ~/.aws, ~/.gnupg, ~/.kube, ~/Library/Keychains, the sign-ins of gcloud,
Azure, DigitalOcean and 1Password, and browser profiles. Each grant is written to iohr's
permissions.log with where it came from (a flag, the environment, the config, trusted.toml or
the card) and the path, never what was read.
Attach a failed command's output
A zsh hook cannot see what a command printed, so by default no output is sent. After a command fails and you ask something like "why did that fail", the menu offers two ways to add it:
- Re-run with output shows the exact command and asks first, starting on No. It runs it once, for at most 10 seconds, and keeps the last 16 KiB of what it printed.
- Paste output reads what you paste, up to Ctrl-D.
Either way the output is redacted (passwords, tokens, URLs, host names and IP addresses), cut to the last 8 KiB or 200 lines when it is sent, and goes with the next question only.
Modes
Press Shift+Tab on a ? line to switch the mode. The prompt says which one is on, and every
question carries it.
| Mode | What Io may do |
|---|---|
| manual | Read files, and ask you before each command it wants to run. The default at a terminal |
| plan | Read only: it reads files and answers with a plan, and changes and runs nothing |
| auto | Run commands that your rules do not forbid, without asking. A deny rule and the secrets list still win |
--mode, [ask] mode and IOHR_ASK_MODE set where it starts. Without a terminal there is
nobody to ask, so only what a rule allows runs, and what it refused is said after the answer.
IO.md: notes for a folder
An IO.md (or io.md) holds what you want Io to know about a folder: what the project is, how to
build and test it, rules to keep. ? and ?? read every IO.md from the folder you are in up to
the project root (the nearest folder with inorbit.toml, .inorbit/ or atlas/, else the git
root, and never past your home folder), and the nearest one wins. One more IO.md in iohr's config
folder applies to every project.
Each file is cut at 4 KiB and all of them together at 8 KiB, nearest first, and secrets in them are scrubbed before they are sent. A file that is a symlink is skipped. The notes shape the answer but never widen what Io may read or run.
iohr context # the IO.md files ? reads here
iohr context --full # and the text that goes to the modeliohr project init writes a starter IO.md at the project root and never overwrites one you have;
--no-io-md skips it.
Your site as sources
When a project was made with iohr project init --crawl and a site's address, ? and ?? also
give Io the five passages of that site that best match the question, each with its page address,
so an answer about the site can say where it came from. The crawl and its index stay on your
machine. iohr atlas search searches the same index yourself. How the crawl works is in
Reading your site.
Answers from your Roles
On macOS and Linux. A project's Roles are the agents in its atlas/roles/ folder, such as
security and an engineer for its language. On a terminal, iohr on its own joins the project's
session, starting it if none runs, and gives you your shell with a floating panel over it.
iohr session joins it without the panel. iohr stop ends the session and closes the panel, and
your shell stays open.
The session runs as a runner of its own, signed in as the profile session. Set it up once:
iohr login --profile session
iohr --profile session runner register --name my-mac-sessionWithout them the session stops at once and says which one is missing.
While the session runs, every ? and ?? asked in the project's folder also goes to each of its
Roles. They answer at the same time as Io, and each answer is drawn as its own card under Io's as
it arrives. --role security,go on the ? line asks only those Roles. A Role that fails says why
in its card. Ctrl-C stops the wait without stopping the Roles; iohr stop ends them. With no
session, or with --json, --menu, --dry-run, --allow-edits, --mode auto or a --role
the session does not run, Io answers alone, as before.
A Role answers read-only, and in plan mode when you asked in plan mode. Each Role keeps two plain files in the project, sent nowhere:
- a handoff note,
.inorbit/handoff/<role>.md, with what it was last asked and what it said, replaced after each turn; - a memory folder,
.inorbit/memory/<role>/, where you can add memories by hand. Every Role turn reads the note and the newest 8 memories.
To have one question answered in a Role without a session, name it:
iohr ask --role security "is this config safe to commit"iohr looks for the Role in the project, then in your account, then in the built-in ones, so the
built-in Roles work offline. A name it cannot find stops the run (exit 2). The Role brings its
own text and model (--model and [ask] model still win) and never widens what Io may read or
run. --job ID with --role gives the Role its brief for that job.
The chat box in the panel
Only in iohr-preview, zsh only. The panel gets a framed box
at the bottom of the terminal for ? and ??:
?at an empty prompt moves to the box, and one Enter sends the question. It still lands in your shell history.- While Io answers, a row shows what it is doing, such as "reading 3 files", with a moving bar and the time. Esc or a click on Stop stops the answer, and Ctrl-C still does.
- Shift+Tab changes the mode, and Up brings back the last question.
- Option+h (⌥h) folds the box to a corner chip and brings it back, in every terminal. On Linux it
is Alt+h. Ctrl-G then
cdoes the same. [panel] chatinconfig.toml("on","hidden"or"off") orIOHR_PANEL_CHATsets how it starts.- While the box shows, the panel takes the mouse for its buttons, so hold Option or Shift to select text.
What is sent
To your provider, and nothing else:
| What | Limit |
|---|---|
| Your question | 2 KiB |
| The folder's path | 1 KiB |
| The names at the top of the folder | 60 names and 2 KiB. Dotfiles are left out except .inorbit, .github, .gitignore and .claude, and so are names the folder's own .gitignore hides. Never file contents |
| The last command and its exit status | The command at 1 KiB |
| In a project: the branch and last commits | The branch, the last 5 commits and the change counts, at most 2 KiB |
| Output, only when attached | The last 8 KiB or 200 lines, redacted |
IO.md notes | 8 KiB, secrets scrubbed |
| Your site's passages, when crawled | The best five for the question |
| The whole message | 24 KiB |
That message holds names, never file contents. While it answers, Io's read-only tools can open files in the folders it may read, and what they read goes to your provider as part of the answer. iohr sends nothing to InOrbit and keeps no record of your questions or answers; the only copies are a Role's handoff note in a session and, in a project, your answers to the questions the card asked you.
From a script
iohr ask "question" is the same thing without the hook: it streams the answer to the
terminal. It works with Claude Code, or with Codex when you set [ask] agent; the card and the
? hook are Claude Code only.
iohr ask "what does this error mean" --output-file build.logWith --json you get the answer, the command it suggested, the questions it asked back and what
of your context was sent, as data, never the text of your output or notes.