Public CLI + polished TUI coding agent for users with a Ulam Alloy subscription/API key.
It is designed to feel like Codex or Claude Code on the local machine: the hosted Ulam Alloy model plans and requests tool calls; the terminal executes filesystem, shell, git, patch, test, and MCP tools locally under user-controlled safety policy. The hosted Alloy gateway remains authoritative for authentication, subscription status, rolling limits, hidden routing, receipts, and billing.
ulam╭ Ulam Alloy Terminal v0.5.0 ─────────────────────────────────────╮
│ model ulam/alloy effort medium mode edit yes off key:set │
│ repo my-app session new usage: 5h $2.64 · 7d $8.80 │
│ Type a task, or /help. Coding uses /v1/responses and local tools │
╰─────────────────────────────────────────────────────────────────╯
› fix the failing billing test and summarize the diff
v0.5.0 focuses on the user experience needed for a public terminal product:
Polished curses TUI with header, usage/status area, sidebar, and prompt composer
Tool cards for reads, searches, patches, shell commands, receipts, and quote events
Approval cards with approve/view/reject/quit flow
Prompt history with Up/Down and PageUp/PageDown scroll
First-run login guidance inside the TUI
/session, /resume, /new, /status, /limits, /budget, /git, and /diff commands
TUI-safe ask_user callback instead of breaking curses with stdin input
25-test validation suite including new TUI helper tests
The coding agent still defaults to POST /v1/responses for tool-loop work. Plain text chat can still use Chat Completions for compatibility.
From source:
unzip ulam-alloy-terminal-v0.5.0.zip
cd ulam-alloy-terminal-v0.5.0
python -m pip install -e .Installed commands:
ulam
alloy
alloy-term
alloy-terminal
ulam login --api-key "ulam_sk_live_..."
ulam account
ulam usage --limit 20
ulam modelsEnvironment variables are also supported:
export ULAM_API_KEY="ulam_sk_live_..."
export ULAM_API_BASE_URL="https://api.ulam.ai/v1"Launch/deployment aliases are accepted too:
export ALLOY_API_KEY="ulam_sk_live_..."
export ALLOY_URL="https://api.ulam.ai" # normalized to /v1 automaticallyOpen the TUI:
ulamor explicitly:
ulam tuiRun one coding task directly:
ulam "inspect this repo and explain the architecture"
ulam --mode edit "fix the failing test and summarize the diff"
ulam --mode auto --yes "run the narrowest relevant test and fix the failure"Use plain chat:
ulam chat "Write a short launch announcement"
ulam --effort high chat "Think through this API design carefully"Inside ulam / ulam tui:
/help show commands
/quit exit
/login ulam_sk_... save an API key
/account show current account/subscription payload
/limits show usage windows
/usage show recent usage
/models list public Ulam aliases
/status show local TUI/session state
/budget show quote/budget/receipt state
/git show git status
/diff [path] show git diff
/sessions show local sessions
/session show current local session JSON
/resume [id|last] resume a local session
/new start a fresh local session
/effort low|medium|high|xhigh change reasoning effort
/mode ask|edit|auto|full change local safety mode
/yes on|off toggle auto-approval for policy-allowed actions
/network on|off allow/block network-like shell commands
/history show prompt history
/clear clear scrollback
Keys:
Up / Down prompt history
PageUp/PageDown scroll transcript
Ctrl-U clear input
Ctrl-L redraw
Any non-command line becomes a coding-agent task in the current workspace.
ask inspect/plan only; no writes or shell execution
edit normal coding with approvals for patches/writes/shell
auto iterative fix/test mode; safe test/status commands can run more freely
full broader shell surface, still policy-checked and path-contained
Built-in local tools:
workspace_info
list_files
read_file
search_text
write_file
apply_patch
run_shell
shell_exec
git_status
git_diff
update_plan
ask_user
The hosted model never receives direct filesystem or shell access. It only receives schemas and tool results; this terminal performs local actions after workspace containment, sensitive-path checks, command allowlists, blocked-pattern checks, network gating, and optional human approval.
The terminal uses Ulam-owned public aliases:
ulam/alloy
ulam/alloy-low
ulam/alloy-medium
ulam/alloy-high
ulam/alloy-xhigh
ulam/alloy-free
Default paid coding-agent calls use:
{
"model": "ulam/alloy",
"reasoning": { "effort": "medium" }
}Normal terminal output sanitizes internal provider/model/cost/margin fields even if an alpha or internal gateway returns them.
The client supports the deployed API surface:
GET /v1/models
POST /v1/responses
POST /v1/chat/completions
GET /v1/me
GET /v1/account
GET /v1/usage
POST /v1/public/signup
POST /v1/billing/checkout
GET /v1/public/free/status
POST /v1/public/free/chat/completions
Optional/future endpoints are supported when present:
POST /v1/quote
GET /v1/limits
GET /v1/usage/limits
When /v1/quote is not available, the terminal shows a clearly marked local estimate only. The gateway remains authoritative for every real subscription, limit, reservation, and debit decision.
The deployed Alloy gateway exposes /v1/responses, and this terminal uses that endpoint by default for coding tasks. Because the deployed endpoint may be a lightweight Responses wrapper over the gateway's Chat Completions path, the terminal sends the full local item history every turn:
user message
assistant function_call
function_call_output
assistant function_call
function_call_output
...
That avoids depending on server-side previous_response_id state and keeps tool-loop behavior deterministic across gateway restarts and deployments.
For deployed compatibility, tool schemas are currently sent in Chat-Completions-style function format even on /v1/responses, because the gateway forwards tools through its chat provider path. This is isolated in client.py / tools.py so switching to fully native Responses tool schemas later is a small change.
The public free demo endpoint is intentionally narrow: no tools, no streaming, no paid quota, no shell or filesystem access.
ulam free-status
ulam try "Explain Ulam Alloy in one paragraph"For local terminal-agent development with no network:
ulam --mock doctor --json
ulam --mock tui
ulam --mock --mode auto --yes run "Inspect this repository"Local sessions are stored under .ulam/state, and transcripts under .ulam/sessions.
ulam sessions list
ulam sessions show <session-id>
ulam sessions export <session-id>
ulam sessions delete <session-id>
ulam --yes sessions clearTerminal-side budget flags are local safety UX only:
ulam --max-session-debit 0.40 run "Fix the failing test"
ulam --require-quote run "Run an expensive-looking task"
ulam --no-budget-check run "Skip local quote preflight"This repo is safe to publish as a client-side terminal agent. It does not contain upstream provider credentials, route config secrets, subscription enforcement, or hidden-routing logic.
The hosted Alloy gateway must remain responsible for:
subscription enforcement
API-key scopes and revocation
billing-cycle / 7-day / 5-hour limits
request reservations and captures
hidden provider/model routing
provider fallbacks
internal economics and margin dashboards