@freeai.fyi/terminal
v0.2.0
Published
FreeAI terminal integration for Claude Code.
Readme
FreeAI Terminal
Standalone Claude Code terminal integration.
Install
npx @freeai.fyi/terminal claude setupCommands
Local dev (from this repo):
cd terminal
npm test
node bin/freeai.js claude setup| Command | What |
| --- | --- |
| freeai claude setup | Locate the real claude, store it in ~/.freeai/claude/config.json, add a marked shell alias/function, then link your FreeAI account by email. Linking is required — the prompt re-asks until a valid email is given (no skip). Pass --email [email protected] to link non-interactively, or the explicit --no-link to opt out (credits then stay unclaimable until you run freeai claude link). |
| freeai claude link [--email …] | Email yourself a magic link that attributes this machine's Claude Code credits to your FreeAI account. Run it any time after setup. |
| freeai claude run [...args] | Internal wrapper used by the alias. It forwards args, cwd, env, stdio, signals, and Claude's exit code. |
| freeai claude restore | Remove the marked shell block. Safe to run repeatedly. |
| freeai claude doctor | Print the resolved Claude path, config/shell/rc paths, then probe the backend pipeline (config → ads → device → account → click-intent) and report an adsWillServe verdict. The account step shows whether this device is linked to your FreeAI account. Pass --no-backend to skip the network probe. |
Account Linking
Credits earned in the terminal accrue to an anonymous device (~/.freeai/device.json)
until that device is linked to a FreeAI account. Linking emails you a magic link
(POST /v1/auth/request-link); clicking it (/v1/auth/verify) sets the device's
user_id, after which Claude Code credits show up in your portal balance. This is
the same device→account flow the Chrome extension popup uses. Until you link, the
account step in freeai claude doctor reports linked: false.
Confirming the link. On a terminal, setup/link send the magic link and
then wait up to ~60s for you to click it, printing ✓ Linked to <email> once
confirmed (or a "didn't see a click yet" hint). Pass --no-wait to fire the
email and return immediately; non-interactive runs never block.
If you skip or abandon linking, freeai claude run prints a single reminder
to stderr (at most once per day) — … aren't linked to an account yet — run
freeai claude link — so credits don't pile up unclaimed. It's local-throttled,
never nags a linked user, and can be silenced with FREEAI_NO_NUDGE=1.
Debugging "no ad shows"
The ad path is silent in normal use, so doctor can be green on the local
machine while no ad serves. Two diagnostics:
freeai claude doctor— theadsWillServefield plus per-stepok/errorshows whether the backend pipeline succeeds (network reachable, ad in rotation, device + click-intent created).FREEAI_DEBUG=1 claude— traces to stderr whether the wrapper ran and which step, if any, caused it to fall back to plainclaude. Nofreeai[debug]output means the shell alias isn't active (type claudeto confirm).
setup adds a marked, reversible shell alias/function so claude ... becomes
freeai claude run .... zsh/bash use:
alias claude="freeai claude run"fish uses an equivalent claude function that forwards $argv.
Uninstall
freeai claude restore # remove the shell alias/function
# restart your shell, or source your rc
npm rm -g @freeai.fyi/terminal # remove the CLI (if installed globally)
rm -rf ~/.freeai # optional: delete local state (device + config)restore removes only the marked shell block; it never touched your real
claude binary, the npm shim, or ~/.claude/settings.json, so Claude Code keeps
working unchanged. If freeai is already gone, delete the marked block from your
rc file by hand. Deleting ~/.freeai removes the device credentials — link your
account by email first (freeai claude link) if you want unlinked earnings to
follow your account.
Claude Code Integration
Reference surfaces:
- Claude Code status line docs: https://code.claude.com/docs/en/statusline
- Claude Code
--settingsCLI docs: https://code.claude.com/docs/en/cli-reference
The wrapper launches the real Claude Code binary with a temporary --settings
file containing a FreeAI statusLine command. It preserves any user-supplied
--settings value by parsing and merging it into the temporary settings file,
then chains any pre-existing effective user/project/local statusLine.
The status line command receives Claude Code's JSON status payload on stdin. It
uses transcript_path plus structural transcript rows to decide whether Claude
is actively thinking. When active, it prints one clickable OSC 8 ad· <line>
that points at a /v1/go/:token URL from /v1/clicks/intent. When idle, it
prints only the user's original status line, or nothing.
It never edits the real Claude binary, npm shim, or persistent
~/.claude/settings.json. If config, ad fetch, device registration, click-intent
creation, settings parsing, or any other FreeAI preparation step fails, run
executes Claude unchanged.
Hooks are intentionally not used in v1. The supported integration surface is
Claude Code statusLine plus a session-scoped --settings file.
State And Billing
Runtime state is stored under ~/.freeai/claude/sessions/<session-id>/ and is
removed when Claude exits. Device credentials are stored in ~/.freeai, matching
the existing Chrome extension device-credit backend.
An impression is emitted to /v1/events only after 5 continuous active seconds
with a fresh statusline heartbeat. Clicks use /v1/clicks/intent tracking URLs;
the terminal client does not self-report click counts through /v1/events.
Backend Configuration
The default API base is the production Supabase Edge Function. It can be
overridden with ~/.freeai/config.json:
{
"backendBaseUrl": "http://127.0.0.1:8787"
}or with FREEAI_BASE when no config file override is set.
Tests
make test-terminal
# or
cd terminal && npm testEnd-to-end across surfaces ("watch your balance climb"): to earn against a local API and watch a portal balance update live, run the client with
FREEAI_BASE=http://localhost:8787and follow../DEVNET.md(make devnet+make devnet-earn).
