A small TypeScript coding-agent MVP designed to sit between:
ferryllmas the local LLM gatewaywinuxshas the Windows-friendly shell execution layer
The MVP is intentionally small: a CLI agent loop, OpenAI-compatible chat-completions and Responses API clients, session persistence, transcripts, and a focused tool set for reading, searching, patching, writing, and running commands.
npm install
npm run build
npm run verifynpm run verify typechecks source and tests, runs the test suite, builds, and checks the built CLI help output.
Start ferryllm separately, then run:
set OPENAI_BASE_URL=http://127.0.0.1:3000/v1
set OPENAI_API_KEY=dummy
set WINUXCODE_MODEL=gpt-4o
npm run dev -- "inspect this project and suggest one improvement"On PowerShell:
$env:OPENAI_BASE_URL = "http://127.0.0.1:3000/v1"
$env:OPENAI_API_KEY = "dummy"
$env:WINUXCODE_MODEL = "gpt-4o"
npm run dev -- "run typecheck and fix issues"Check local wiring without starting an agent turn:
npm run dev -- config-show
npm run dev -- --json config-show
npm run dev -- --version
npm run dev -- doctor
npm run dev -- --json doctordoctor includes a safety check with the resolved approval policy, permission profile, and shell tool mode, plus a git worktree check for the selected workspace. doctor --json includes a top-level ok summary.
List enabled tools:
npm run dev -- tools
npm run dev -- --dry-run tools
npm run dev -- --json toolstools --json includes the resolved permission profile and shell tool mode alongside the tool definitions.
Inspect or clear persisted message history:
npm run dev -- session-info
npm run dev -- --json session-info
npm run dev -- session-clearsession-info reports malformed or oversized session files as valid: false so they can be inspected before clearing. JSON output includes saved metadata, current runtime metadata, message role counts, and compatibility warnings.
Inspect transcript file state:
npm run dev -- transcript-info
npm run dev -- --json transcript-info
npm run dev -- transcript-cleartranscript-info reports size and, when the file is within transcriptMaxBytes, event count, event type counts, tool duration totals, first/last event timestamps, malformed JSONL line count, and whether the analyzed JSONL is valid.
Create winuxcode.config.json in the workspace:
npm run dev -- initIt writes:
{
"api": "chat",
"approvalPolicy": "never",
"permissionProfile": "workspace-write",
"shellTool": "enabled",
"baseUrl": "http://127.0.0.1:3000/v1",
"apiKey": "dummy",
"model": "gpt-4o",
"shell": "winuxsh",
"session": ".winuxcode/session.json",
"transcript": ".winuxcode/transcript.jsonl",
"maxSteps": 12,
"maxToolCallsPerStep": 16,
"llmTimeoutMs": 120000,
"llmMaxRetries": 2,
"shellTimeoutMs": 120000,
"writeFileMaxBytes": 1048576,
"patchMaxBytes": 1048576,
"sessionMaxBytes": 5242880,
"sessionMaxMessages": 400,
"transcriptMaxBytes": 10485760,
"transcriptMaxEventBytes": 1048576
}CLI flags override environment variables, which override config file values.
Use "api": "responses" or --api responses to target ferryllm's /v1/responses endpoint.
Use "approvalPolicy": "on-request", WINUXCODE_APPROVAL_POLICY=on-request, or --approval-policy on-request to opt into approval-request vocabulary for future interactive flows. The current MVP still refuses blocked commands.
Use "permissionProfile": "read-only" or --permission-profile read-only to expose only read/search/git tools. --dry-run is a shortcut for read-only mode.
Use "shellTool": "disabled", WINUXCODE_SHELL_TOOL=disabled, or --shell-tool disabled to keep write/patch tools while omitting run_shell.
Use "session": ".winuxcode/session.json" or --session .winuxcode/session.json to persist message history across runs. Session files record the workspace, model, API mode, permission profile, and shell tool mode, and winuxcode warns when a resumed session differs from the current runtime.
session-info shows the same metadata warnings without starting an agent turn.
Use "transcript": ".winuxcode/transcript.jsonl" or --transcript .winuxcode/transcript.jsonl to capture session events. Tool result events include durationMs.
Use --no-session or --no-transcript to temporarily disable configured persistence for one run.
Use "maxToolCallsPerStep" / --max-tool-calls-per-step to cap how many tools one assistant turn may request.
Use "llmTimeoutMs" / --llm-timeout-ms and "llmMaxRetries" / --llm-max-retries to control LLM request timeout and retry behavior.
Use "shell": "winuxsh", WINUXCODE_SHELL, or --shell powershell to choose the shell executable.
Use "shellTimeoutMs" / --shell-timeout-ms to set the default and maximum timeout for run_shell.
run_shell output includes the resolved timeout and output byte cap used for the command.
Use "writeFileMaxBytes" / --write-file-max-bytes to cap write_file content size.
Use "patchMaxBytes" / --patch-max-bytes to cap apply_patch payload size.
Use "sessionMaxBytes" / --session-max-bytes to cap session file load/save size.
Use "sessionMaxMessages" / --session-max-messages to cap session history length.
Use "transcriptMaxBytes" / --transcript-max-bytes to cap transcript file size.
Use "transcriptMaxEventBytes" / --transcript-max-event-bytes to cap one transcript event.
Runtime numeric settings also have hard caps: 100 agent steps, 64 tool calls per assistant turn, 10 LLM retries, 10 minute LLM/shell timeouts, 10 MiB write/patch/transcript-event payload limits, 50 MiB session files, 100 MiB transcript files, and 2000 session messages.
By default, shell commands run through winuxsh -c <command>. Override with:
$env:WINUXCODE_SHELL = "powershell"
npm run dev -- --shell powershell "run tests"The MVP has explicit approval policy vocabulary and permission profiles, blocks obviously destructive shell commands, can disable the shell tool independently, caps shell command runtime, caps tool output and text-read limits, caps transcript events, redacts common secrets in diagnostics/session/transcript/tool output, and keeps file tools inside the selected workspace. File tool outputs also redact explicit secrets in returned path metadata. Tool output also redacts the configured API key as an explicit secret before it is returned to the model. Patches use unified diff or Codex-style patch envelope format and are applied by a small built-in patcher; moved patch outputs include both the new path and original from path.
Blocked shell commands include a structured permissionRequest object for a future approval UI, but the current MVP still refuses the command.
git_status returns both raw porcelain output and structured branch, entries, and clean fields. Entries include the raw two-character code plus split index and worktree status fields. Branch metadata includes upstream plus ahead/behind counts when git reports them.
git_diff returns raw diff output plus changed, staged, path, and per-file numstat metadata.
If the workspace has AGENTS.md files, winuxcode reads the root and nested files into the initial system prompt for new sessions.
winuxcode CLI
-> OpenAI-compatible HTTP clients
-> ferryllm /v1/chat/completions or /v1/responses
-> model/provider route
winuxcode tools
-> list_files/read_file/search_text/git_status/git_diff/apply_patch/write_file
-> run_shell through winuxsh -c
-> JSONL transcript and JSON session store
Next useful upgrades:
- Add
winuxsh --json -csupport upstream so shell output is structured. - Add streaming output for the Responses API client.
- Add approval policy/session-level accept controls.
- Keep expanding patcher and command safety behavior tests.
Reference analysis and porting notes live in docs/reference-notes.md.