Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
9425be3
ci(Devcontainer): update
k1dav Jul 24, 2026
fbabdb7
feat(chat): refine agent workspace UI
k1dav Jul 24, 2026
497737e
feat(chat): improve session interface
k1dav Jul 24, 2026
83e6c9f
feat(chat): add clickable terminal shortcuts
k1dav Jul 24, 2026
590d07c
feat(chat): queue messages while agent is running
k1dav Jul 24, 2026
7b159fe
style(chat): expand message input width
k1dav Jul 24, 2026
b4f9b0f
feat(chat): improve message rendering and navigation
k1dav Jul 25, 2026
0cdeffb
feat(chat): track connection status
k1dav Jul 25, 2026
3474280
feat(chat): enhance message queue controls
k1dav Jul 25, 2026
6b512d6
fix(chat): improve mobile message input
k1dav Jul 25, 2026
3d9f60e
feat(chat): manage queued tasks and control input
k1dav Jul 25, 2026
9228619
feat(chat): organize conversations by task
k1dav Jul 25, 2026
aae0619
feat(chat): show live session activity details
k1dav Jul 25, 2026
ad3cf03
fix(chat): improve mobile viewport behavior
k1dav Jul 25, 2026
a8a3654
feat(chat): reflect session state in document title
k1dav Jul 25, 2026
2db762f
fix(chat): improve terminal output link handling
k1dav Jul 26, 2026
0922bab
feat(chat): improve connection and message recovery
k1dav Jul 26, 2026
e9d5dd3
feat(chat): improve attachment and message input flow
k1dav Jul 26, 2026
4321113
feat(chat): clarify task activity and tool output
k1dav Jul 26, 2026
fd3001a
fix(termexec): keep emulator cursor in sync with wide characters
k1dav Jul 26, 2026
35ad9c5
fix(screentracker): trim previous turn output leaked by TUI re-renders
k1dav Jul 26, 2026
5159967
feat(jsonlwatcher): add agent session JSONL watcher
k1dav Jul 26, 2026
3922c17
feat(httpapi): add message queue, rich messages, session export, and …
k1dav Jul 26, 2026
70be434
feat(chat): add session JSONL download
k1dav Jul 26, 2026
4b17a11
fix(chat): remove fixed-height scroll cap on agent messages
k1dav Jul 26, 2026
e480876
docs: add CLAUDE.md
k1dav Jul 26, 2026
397736b
feat(chat): add terminal view and session explorer
k1dav Jul 26, 2026
f08a3f3
fix(chat): remove run again action
k1dav Jul 26, 2026
40962f6
fix(chat): wrap long agent output lines
k1dav Jul 26, 2026
bf97314
fix(chat): simplify header controls and button cursors
k1dav Jul 26, 2026
58f360c
fix(chat): preserve explorer tab selection
k1dav Jul 26, 2026
e9c6709
fix(chat): render tables in markdown preview
k1dav Jul 26, 2026
0e9e8e2
fix(httpapi): prevent double-close panic in EventEmitter
k1dav Jul 26, 2026
d3a7d20
fix(httpapi): eliminate TOCTOU race in getMessages
k1dav Jul 26, 2026
5bf4860
fix(termexec): fix data race, PTY leak, and double-Wait
k1dav Jul 26, 2026
184aec7
fix(server): guard nil process in ACP shutdown path
k1dav Jul 26, 2026
812bf63
fix(screentracker): fix Opencode off-by-one in screenDiff
k1dav Jul 26, 2026
a7220b1
fix(jsonlwatcher): flush completed messages after each poll cycle
k1dav Jul 26, 2026
36ffb56
feat(httpapi): add title and background-tasks endpoints
k1dav Jul 26, 2026
cff7fe2
feat(chat): show background task output details
k1dav Jul 26, 2026
ca214a9
fix(httpapi): finalize background task statuses
k1dav Jul 26, 2026
06a8deb
fix(chat): align explorer with search toolbar
k1dav Jul 26, 2026
3bd16d8
feat(httpapi): replace /session/export with /timeline endpoint
k1dav Jul 26, 2026
a6d9c3d
feat(termexec): add SwappableProcess for in-place agent replacement
k1dav Jul 26, 2026
5f80cf2
feat(mcpconfig): add MCP config stores for Claude and Codex
k1dav Jul 26, 2026
58bd4ce
feat(httpapi): add GET/PUT /mcp endpoints with optional agent restart
k1dav Jul 26, 2026
72b2ac4
feat(chat): add MCP server configuration tab in the explorer
k1dav Jul 26, 2026
cb55228
feat(chat): add task Markdown preview and centralize UI copy
k1dav Jul 26, 2026
5610134
chore(chat): remove unused alert and checkbox components
k1dav Jul 26, 2026
afa72a8
docs(httpapi): enrich OpenAPI documentation for /mcp endpoints
k1dav Jul 26, 2026
659640a
ci: enable release builds on this fork
k1dav Jul 26, 2026
60a721f
feat(mcp): add server management and profiles
k1dav Jul 26, 2026
62664b6
ui: render tool call status on one line
k1dav Jul 26, 2026
336a91c
server: add runtime webhook configuration
k1dav Jul 26, 2026
51ac1be
ui: configure webhooks from session explorer
k1dav Jul 26, 2026
124ea77
feat: add Kimi Code CLI support
k1dav Jul 26, 2026
4a11525
feat(ui): improve message and tool activity rendering
k1dav Jul 26, 2026
ef42ec6
docs(readme): document fork features and releases
k1dav Jul 26, 2026
b409f5e
feat(update): add self-update command
k1dav Jul 31, 2026
03728d4
feat(cmd): register update subcommand
k1dav Jul 31, 2026
0300919
feat(httpapi): add GET /usage endpoint with Anthropic and OpenAI support
k1dav Jul 31, 2026
aba0c55
feat(httpapi): register /usage route
k1dav Jul 31, 2026
58ffdf0
chore: regenerate openapi.json
k1dav Jul 31, 2026
4857402
feat(httpapi): add Bearer token authentication middleware
k1dav Jul 31, 2026
e09ffde
feat(server): add --api-token flag for API authentication
k1dav Jul 31, 2026
b8d9d35
fix(chat): show interactive prompt dialogs in chat UI
k1dav Jul 31, 2026
4b20370
docs(readme): document new features
k1dav Jul 31, 2026
dbe433a
refactor(server): --api-token without value auto-generates token
k1dav Jul 31, 2026
276746a
fix(httpapi): /usage falls back to any available provider
k1dav Jul 31, 2026
97456c3
feat(httpapi): support Codex auth.json for /usage endpoint
k1dav Jul 31, 2026
af72881
refactor(httpapi): remove /usage provider fallback
k1dav Jul 31, 2026
61150ad
fix(chat): always show PTY process output in task activity
k1dav Jul 31, 2026
27db239
fix(httpapi): return error instead of os.Exit in SetupProcess
k1dav Jul 31, 2026
eeca062
refactor: replace golang.org/x/xerrors with standard library
k1dav Jul 31, 2026
3f932f8
test: add benchmarks for screentracker and termexec hot paths
k1dav Jul 31, 2026
e314523
feat(chat): remove interactive prompt option detection
k1dav Jul 31, 2026
5faf111
chore: apply gofumpt formatting fixes
k1dav Jul 31, 2026
7659c14
feat(webhook): replace HMAC signing with custom payload templates
k1dav Jul 31, 2026
9fe0524
feat(httpapi): add POST /restart endpoint for agent process restart
k1dav Jul 31, 2026
d6dd611
feat(chat): add agent restart button to Explorer header
k1dav Jul 31, 2026
cf6ca33
fix(update): verify release binary checksums
k1dav Jul 31, 2026
9364190
feat(httpapi): expose agent lifecycle state
k1dav Jul 31, 2026
a4a069a
docs: update README for webhook templates and restart endpoint
k1dav Jul 31, 2026
4d00c73
feat: add Reset() to EventEmitter, Conversation, PTY, ACP
k1dav Jul 31, 2026
9e36627
feat(httpapi): replace POST /restart with DELETE /messages
k1dav Jul 31, 2026
3cd34ad
feat(chat): update UI to use DELETE /messages
k1dav Jul 31, 2026
56a443f
chore: regenerate openapi.json
k1dav Jul 31, 2026
ac43014
docs(readme): update /restart → DELETE /messages in endpoint list
k1dav Aug 1, 2026
8dc7304
feat(httpapi): add request logging middleware
k1dav Aug 1, 2026
1148a8b
perf(chat): throttle queue refresh to 30s intervals
k1dav Aug 1, 2026
eebc177
fix: use literal angle brackets in openapi.json description
k1dav Aug 1, 2026
ec344b1
fix(server): avoid false PID reuse conflicts
k1dav Aug 11, 2026
d7c25e1
fix(msgfmt): collapse consecutive blank lines in agent output
k1dav Sep 5, 2026
fe4cef7
feat(chat): add semantic status/code-block/highlight CSS tokens
k1dav Sep 5, 2026
3f9e25b
refactor(chat): replace hardcoded amber/emerald/zinc with semantic to…
k1dav Sep 5, 2026
7c4ba16
feat(chat): add token usage tracking and Usage type
k1dav Sep 5, 2026
555fead
feat(chat): header token counter, status tokens, shortcuts menu, cust…
k1dav Sep 5, 2026
87821c3
feat(chat): code block copy button and syntax highlighting
k1dav Sep 5, 2026
33431bd
refactor(chat): split message-list.tsx into modular components
k1dav Sep 5, 2026
7ba34a9
feat(chat): add shadcn Tooltip component and TooltipProvider
k1dav Sep 5, 2026
15bd40e
feat(chat): keyboard shortcuts dialog with ? key trigger
k1dav Sep 5, 2026
07a2683
feat(chat): embed mode status bar with agent name and token count
k1dav Sep 5, 2026
89eb411
feat(chat): replace Suspense fallback with loading skeleton
k1dav Sep 5, 2026
f67b8f8
feat(chat): customizable page title via ?title= query param
k1dav Sep 5, 2026
aeb6a54
fix(chat): remove unused TaskActivity import in task-group.tsx
k1dav Sep 5, 2026
b404337
fix(chat): skip tool grouping when rich interleaving is available
k1dav Sep 5, 2026
261b025
chore: bump version to 0.13.0
k1dav Sep 5, 2026
5ab5bbe
fix(jsonlwatcher): prevent content block loss during FlushCompleted
k1dav Sep 5, 2026
a1290a6
fix(jsonlwatcher): follow Claude Code session parking to find JSONL
k1dav Sep 5, 2026
cd15cb3
fix(httpapi): merge rich message content blocks on re-emit
k1dav Sep 5, 2026
969be7e
fix(jsonlwatcher): switch tailed file when session path changes
k1dav Sep 5, 2026
682aad0
feat(chat): render thinking blocks and per-message markdown toggle
k1dav Sep 5, 2026
194a27f
docs: update README and CHANGELOG for v0.13.0
k1dav Sep 5, 2026
a4d87d1
feat(chat): show terminal action banner for interactive prompts
k1dav Sep 5, 2026
a801f5c
feat(chat): generalized terminal interaction detection
k1dav Sep 5, 2026
0d172e0
feat(chat): comprehensive interactive prompt detection for Claude and…
k1dav Sep 5, 2026
d2b3a7f
feat(chat): interactive option buttons for TUI selection prompts
k1dav Sep 5, 2026
5799e6c
feat(chat): render AskUserQuestion options as clickable buttons
k1dav Sep 5, 2026
fd9e325
feat(chat): handle all interactive option types with action buttons
k1dav Sep 5, 2026
6eb4291
fix(chat): include PTY responses in rich interleaving path
k1dav Sep 5, 2026
1ab07cb
fix(server): safely reclaim stale PID files
k1dav Sep 7, 2026
7030786
fix(chat): place interactive options below messages
k1dav Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM mcr.microsoft.com/devcontainers/go:1-1.24-bookworm

# The base image ships a yarn apt repo with an expired GPG key that breaks
# `apt-get update`; drop it before installing anything.
RUN rm -f /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends shellcheck \
&& rm -rf /var/lib/apt/lists/*

# The image pins GOTOOLCHAIN=local but go.mod requires a newer patch release;
# let Go download the exact toolchain version on demand.
ENV GOTOOLCHAIN=auto

# proxy.golang.org is DNS-hijacked on this network (HiNet safebrowsing) and
# goproxy.io lacks toolchain modules; goproxy.cn mirrors both.
ENV GOPROXY=https://goproxy.cn,direct
14 changes: 14 additions & 0 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "1.7.1",
"resolved": "ghcr.io/devcontainers/features/node@sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6",
"integrity": "sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6"
},
"ghcr.io/shyim/devcontainers-features/bun:0": {
"version": "0.0.1",
"resolved": "ghcr.io/shyim/devcontainers-features/bun@sha256:689eae681aa08981175829a59953ba67a7d311f6a05c15d1bbbcb2da2839827e",
"integrity": "sha256:689eae681aa08981175829a59953ba67a7d311f6a05c15d1bbbcb2da2839827e"
}
}
}
45 changes: 45 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "agentapi",
// Dockerfile removes the base image's expired yarn apt repo and installs
// shellcheck (required by `make lint/shellcheck`)
"build": {
"dockerfile": "Dockerfile"
},
"features": {
// Bun builds the chat UI (see Makefile: `bun run build`, `bun lint`)
"ghcr.io/shyim/devcontainers-features/bun:0": {},
// Node is still needed by Next.js/ESLint tooling under the hood
"ghcr.io/devcontainers/features/node:1": {
"version": "lts"
}
},
"remoteUser": "root",
"containerUser": "root",
// safe.directory: running as root, git refuses the host-owned repo without it
"postCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder} && cd chat && bun install",
"forwardPorts": [3284, 3000, 6006, 2345],
"portsAttributes": {
"3284": {
"label": "agentapi server"
},
"3000": {
"label": "chat UI (next dev)"
},
"6006": {
"label": "storybook"
},
"2345": {
"label": "delve debugger"
}
},
"customizations": {
"vscode": {
"extensions": [
"golang.go",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss"
]
}
}
}
108 changes: 55 additions & 53 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,74 +1,76 @@
name: Build Release Binaries

# Compiles agentapi binaries (with the chat UI embedded) and attaches them
# to the release when one is published. Adapted from upstream coder/agentapi
# for this fork: no repository-owner gate and standard hosted runners.
# make build handles the chat UI build + embed via the sources stamp, so the
# chat UI is only built once across all target platforms.

permissions:
contents: write

on:
release:
types: [published]
push:
branches: [ main ]
workflow_dispatch:
inputs:
create-artifact:
description: 'Create build artifact'
required: true
type: boolean
default: false

jobs:
build:
name: Build Release Binaries
runs-on: ubuntu-latest-8-cores
if: ${{ github.repository_owner == 'coder' }}
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 'stable'
- name: Set up Bun
uses: oven-sh/setup-bun@v2

- name: Set up Bun
uses: oven-sh/setup-bun@v2
- name: Install Chat Dependencies
run: cd chat && bun install --frozen-lockfile

- name: Install Chat Dependencies
run: cd chat && bun install
- name: Run make gen and check for unstaged changes
run: |
make gen
./check_unstaged.sh

- name: Run make gen and check for unstaged changes
run: |
make gen
./check_unstaged.sh
- name: Build binaries
shell: bash
run: |
build_variants=(
"linux amd64 agentapi-linux-amd64"
"linux arm64 agentapi-linux-arm64"
"darwin amd64 agentapi-darwin-amd64"
"darwin arm64 agentapi-darwin-arm64"
"windows amd64 agentapi-windows-amd64.exe"
)

- name: Build and Upload
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
build_variants=(
"linux amd64 agentapi-linux-amd64"
"linux arm64 agentapi-linux-arm64"
"darwin amd64 agentapi-darwin-amd64"
"darwin arm64 agentapi-darwin-arm64"
"windows amd64 agentapi-windows-amd64.exe"
)
for variant in "${build_variants[@]}"; do
read -r goos goarch artifact_name <<< "$variant"

for variant in "${build_variants[@]}"; do
read -r goos goarch artifact_name <<< "$variant"
echo "Building for GOOS=$goos GOARCH=$goarch..."
GOOS="$goos" GOARCH="$goarch" BINPATH="out/$artifact_name" make build
done

echo "Building for GOOS=$goos GOARCH=$goarch..."
CGO_ENABLED=0 GOOS=$goos GOARCH=$goarch BINPATH="out/$artifact_name" make build
done
(
cd out
sha256sum agentapi-* > checksums.txt
)

- name: Upload Build Artifact
if: ${{ inputs.create-artifact }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: agentapi-build
path: ${{ github.workspace }}/out
retention-days: 7
- name: Upload build artifact
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: actions/upload-artifact@v4
with:
name: agentapi-build
path: out/
retention-days: 7

- name: Upload Release Assets
if: ${{ github.event_name == 'release' || github.ref == 'refs/heads/main' }}
run: gh release upload "$RELEASE_TAG" "$GITHUB_WORKSPACE"/out/* --clobber
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ github.event_name == 'release' && github.event.release.tag_name || 'preview' }}
- name: Upload release assets
if: ${{ github.event_name == 'release' }}
run: gh release upload "${{ github.event.release.tag_name }}" out/* --clobber
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## v0.13.0

### Features
- Render Claude thinking blocks as collapsible sections in the task timeline
- Per-message markdown/raw render toggle (replaces global toolbar toggle)

### Fixes
- Merge rich message content blocks on re-emit instead of dropping earlier blocks during Claude delta streaming
- Switch tailed JSONL file at runtime when Claude Code parks a session to a new path
- Reorder resolver priority so ParkedJobID scan runs before direct file check, preventing stale session selection

## v0.12.2

### Fixes
Expand Down
75 changes: 75 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What This Is

AgentAPI is a Go HTTP server that controls coding agents (Claude Code, Aider, Goose, Codex, Gemini, Copilot, Amp, Cursor, Auggie, AmazonQ, Opencode) through terminal emulation. It runs agents in an in-memory terminal emulator, translates HTTP API calls into terminal keystrokes, and parses terminal output into structured messages. It also embeds a Next.js chat web UI.

## Build & Run

```bash
make build # Build binary to out/agentapi (includes chat UI build)
go build -o out/agentapi main.go # Go-only build without chat UI
make embed # Build chat UI and copy into lib/httpapi/chat/ for embedding
make fmt # Format Go code with gofumpt
make gen # Regenerate OpenAPI schema and version (go generate ./...)
make lint # Run all linters (Go, TypeScript, shellcheck, actionlint)
```

Chat UI development:
```bash
cd chat && bun install # Install chat dependencies
cd chat && bun run dev # Start Next.js dev server with Turbopack
cd chat && bun lint # Lint TypeScript
```

## Testing

```bash
go test ./... # Run all Go tests
go test ./lib/httpapi/... # Run tests in a specific package
go test -run TestOpenAPISchema ./lib/httpapi/... # Run a single test
go test ./e2e # Run e2e tests (smoke test)
```

Tests use `CGO_ENABLED=0`. The project uses `testify` (assert/require) and `coder/quartz` for deterministic time mocking. Tests are colocated with source files. E2e tests in `e2e/` use a scripted echo agent that simulates real agent behavior.

## Architecture

### Message Flow
1. User sends message via `POST /message`
2. Server takes a terminal snapshot, sends keystrokes to the agent process
3. A polling loop compares new terminal snapshots against the baseline
4. New content below the baseline becomes the agent's response message
5. SSE events (`GET /events`) stream message and status updates to clients

### Key Packages
- **`lib/httpapi/`** — HTTP server (chi router + huma for OpenAPI). Routes: `/messages`, `/message`, `/status`, `/events` (SSE), `/queue`, `/upload`, `/rich-messages`. The chat UI is embedded via `//go:embed` from `lib/httpapi/chat/`.
- **`lib/screentracker/`** — Core conversation engine. `Conversation` interface with `PTYConversation` implementation. Manages terminal snapshots, screen diffing, message splitting, and status detection (stable vs. changing).
- **`lib/termexec/`** — Terminal process execution. Wraps PTY creation and process lifecycle.
- **`lib/msgfmt/`** — Agent-specific message formatting. Strips echoed user input and TUI elements (input boxes, borders) from terminal output. Each agent type has different formatting quirks.
- **`lib/jsonlwatcher/`** — Watches agent JSONL session logs (Claude, Codex) for rich structured messages (tool calls, thinking, usage data). Runs as a sidecar alongside PTY.
- **`x/acpio/`** — Experimental ACP (Agent Communication Protocol) transport, alternative to PTY.
- **`cmd/`** — CLI commands via cobra/viper. `server` and `attach` subcommands.

### Two Transport Modes
- **PTY (default)**: Runs the agent in a terminal emulator, parses screen output.
- **ACP (experimental)**: Uses the Agent Communication Protocol for structured communication (`--experimental-acp`).

### Adding a New Agent Type
1. Add the `AgentType` constant in `lib/msgfmt/msgfmt.go`
2. Add formatting logic in `lib/msgfmt/` (message box removal, user input stripping)
3. Add readiness detection in `lib/msgfmt/agent_readiness.go`
4. Add alias mapping in `cmd/server/server.go` (`agentTypeAliases`)
5. Add display name in `chat/src/components/chat-provider.tsx`

### Exhaustive Switch/Map Enforcement
The `exhaustive` golangci-lint checker is enabled for both switches and maps. When adding a new `AgentType` or enum value, all switch statements and map literals over that type must be updated or the linter will fail.

## Conventions

- OpenAPI schema is auto-generated: `go run main.go server --print-openapi dummy > openapi.json` (via `go generate`)
- The chat UI build output goes to `lib/httpapi/chat/` with a magic base path placeholder that gets replaced at runtime
- Environment variables use `AGENTAPI_` prefix (e.g., `AGENTAPI_ALLOWED_HOSTS`)
- Server defaults: port 3284, chat at `/chat`, docs at `/docs`
Loading