Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ on:
release_name:
description: "Release name to create when publish_release is true"
required: true
default: "Agent Studio Code 0.0.2 Beta"
default: "Agent Code 0.0.2 Beta"

concurrency:
group: release-macos
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cc-shell
# Agent Code

This codebase is written and developed by AI. Future you will pick up where past you left off, with no shared memory beyond what's in the repo.

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cc-shell
# Agent Code

This codebase is written and developed by AI. Future you will pick up where past you left off, with no shared memory beyond what's in the repo.

Expand Down
2 changes: 1 addition & 1 deletion CODEX.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# cc-shell
# Agent Code

This codebase is written and developed by AI. Future you will pick up where past you left off, with no shared memory beyond what's in the repo.

Expand Down
20 changes: 8 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
# cc-shell
# Agent Code

`cc-shell` is an agent-first editor for heavy users of Claude Code and Codex.

The working name is `cc-shell`. The product is planned to be renamed to
**Agent Code**. Some repository paths, package names, and UI labels may still
use `cc-shell` during the transition.
Agent Code is an agent-first editor for heavy users of Claude Code and Codex.

This is not another "make Claude Code look nicer" wrapper. It is an
agentic development platform built on the opposite assumption: the agent
Expand All @@ -22,7 +18,7 @@ of them hit the same two failure modes:

That leads to tools that look polished but are materially weaker.

`cc-shell` takes a harder line:
Agent Code takes a harder line:

- Claude Code should still feel like Claude Code.
- Codex should still feel like Codex.
Expand All @@ -39,7 +35,7 @@ The best agent editor is a platform that runs the real Claude Code and the
real Codex under the hood, preserves their behavior, and then layers better
workspace primitives on top for people who spend all day in agent loops.

That means `cc-shell` is built for:
That means Agent Code is built for:

- parallel agent work
- persistent sessions
Expand All @@ -61,11 +57,11 @@ That approach is bad on two fronts:
If you strip things down to "send message, get message back", you lose most
of what makes those tools good in practice.

`cc-shell` is explicitly trying not to do that.
Agent Code is explicitly trying not to do that.

## How It Works

`cc-shell` runs Claude Code and Codex headlessly under the hood.
Agent Code runs Claude Code and Codex headlessly under the hood.

But "headless" here does **not** mean using a minimal session API and
pretending that is the product.
Expand All @@ -82,7 +78,7 @@ The architecture combines:
- transcript parsing
- session management

This lets `cc-shell` surface the real commands, flows, and tools from Claude
This lets Agent Code surface the real commands, flows, and tools from Claude
Code and Codex in an API-like way without collapsing them into a toy chat
interface.

Expand All @@ -95,7 +91,7 @@ In practice, the stack includes:

## What This Project Is

`cc-shell` is:
Agent Code is:

- an Electron desktop shell for agent-heavy development
- a multi-session workspace for Claude Code, Codex, and terminals
Expand Down
2 changes: 1 addition & 1 deletion docs/design/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `docs/design/` — sources of truth for non-obvious system designs

Files in this directory describe **what cc-shell's most complicated subsystems are and why they are shaped the way they are.** They are referenced by inline code comments and treated as authoritative. They are *not* changelogs, *not* running notes, *not* blow-by-blow histories of how a fix was derived.
Files in this directory describe **what Agent Code's most complicated subsystems are and why they are shaped the way they are.** They are referenced by inline code comments and treated as authoritative. They are *not* changelogs, *not* running notes, *not* blow-by-blow histories of how a fix was derived.

## DO NOT change these files lightly

Expand Down
18 changes: 9 additions & 9 deletions docs/design/ghost-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@

## What ghost is, in plain English

cc-shell talks to the agent (Claude Code, Codex) two ways at the same time:
Agent Code talks to the agent (Claude Code, Codex) two ways at the same time:

- It **reads the agent's authoritative transcript file** (Claude Code's `~/.claude/projects/<proj>/<sid>.jsonl`, Codex's rollout JSONL). That file is the durable record of what happened — but it's written *lazily*. Claude Code batches transcript writes every 100 ms (10 ms for remote sessions); Codex queues writes through a tokio mpsc channel that drains on flush barriers. The file is structurally behind reality.
- It **observes the agent's network traffic via a per-session mitmproxy.** The proxy emits a flat semantic stream — `turn_started`, `text_delta`, `tool_input_delta`, `tool_input_finalized`, `block_completed`, `tool_result`, `turn_completed`, etc. — as the model's reply streams in. The proxy is roughly real-time.

The proxy is ahead. The file catches up. Eventually they agree.

A **ghost** is a provisional `ClaudeEntry` cc-shell mints from the proxy stream, tagged `_atp.origin = 'ghost'`, with a deterministic uuid (`g-<turnId>-<blockIndex>`). It exists to bridge the gap between the two sources without producing duplicate-render bugs. When the authoritative JSONL entry lands, the ghost is *superseded* and dropped from the visible set. If it never lands, the ghost is *orphaned* and (sometimes — see the predicate) surfaces as the only record of what the proxy observed.
A **ghost** is a provisional `ClaudeEntry` Agent Code mints from the proxy stream, tagged `_atp.origin = 'ghost'`, with a deterministic uuid (`g-<turnId>-<blockIndex>`). It exists to bridge the gap between the two sources without producing duplicate-render bugs. When the authoritative JSONL entry lands, the ghost is *superseded* and dropped from the visible set. If it never lands, the ghost is *orphaned* and (sometimes — see the predicate) surfaces as the only record of what the proxy observed.

The ghost primitive is general-purpose and lives in the standalone `agent-transcript-parser` package (`./packages/agent-transcript-parser/src/ghost.ts`, doc at `./packages/agent-transcript-parser/docs/ghost.md`). cc-shell's job is to wire it up: mint ghosts from semantic events, persist to disk, reconcile against JSONL, decide when to render.
The ghost primitive is general-purpose and lives in the standalone `agent-transcript-parser` package (`./packages/agent-transcript-parser/src/ghost.ts`, doc at `./packages/agent-transcript-parser/docs/ghost.md`). Agent Code's job is to wire it up: mint ghosts from semantic events, persist to disk, reconcile against JSONL, decide when to render.

## Why ghost exists

Expand All @@ -22,7 +22,7 @@ The naive alternatives all fail:
| Approach | Failure |
|---|---|
| Render only the JSONL file. | Visible 100 ms+ delay between the model talking and the screen showing anything. Worse during slow batched flushes or large tool_results. |
| Render only the proxy stream. | No durable record. Closing cc-shell mid-turn loses the partial turn. Resume after crash has nothing to show. |
| Render only the proxy stream. | No durable record. Closing Agent Code mid-turn loses the partial turn. Resume after crash has nothing to show. |
| Render BOTH unconditionally — JSONL above, proxy below. | The same sentence appears twice during the lag window. Documented historical bug on Codex (`docs/superpowers/plans/2026-04-20-rendering-fixes.md`). |

The design idea was: one merged feed. Authoritative entries from the file, plus provisional ghost rows when the proxy is ahead, with automatic supersedure when the file catches up. The user sees one row that transitions seamlessly from "live preview" to "committed."
Expand All @@ -33,7 +33,7 @@ That plan was never fully completed (see [Phase 3: deliberately out of scope](#p

This is the most-confusing part of the current architecture, and it's load-bearing for every rule below.

In cc-shell today, the **live current turn** (the assistant's in-flight reply) is rendered by `SemanticStreamingTurn`, which reads `runtime.semantic.currentTurn` directly off the semantic reducer. **Not from ghosts.** See `src/renderer/src/features/feed/ui/semantic/StreamingTurn.tsx` and the call site at `src/renderer/src/features/feed/ui/Feed.tsx:912-916`.
In Agent Code today, the **live current turn** (the assistant's in-flight reply) is rendered by `SemanticStreamingTurn`, which reads `runtime.semantic.currentTurn` directly off the semantic reducer. **Not from ghosts.** See `src/renderer/src/features/feed/ui/semantic/StreamingTurn.tsx` and the call site at `src/renderer/src/features/feed/ui/Feed.tsx:912-916`.

Ghosts exist *in parallel* with that live render. Every semantic event that updates `currentTurn` ALSO mints / updates a corresponding ghost via `ghostsFromSemanticTurn` in `src/renderer/src/workspace/ghosts.ts`. The two paths don't collide because the render predicate (below) explicitly excludes any ghost whose `turnId === currentTurn.turnId` — `SemanticStreamingTurn` owns that turn, ghosts can't surface for it.

Expand All @@ -42,7 +42,7 @@ So the practical question for the ghost system is: **what is rendering ghost row
Answer: a small set of fallback cases where `SemanticStreamingTurn` can't help.

1. **JSONL stuck mid-turn.** The agent process gets wedged or its writer backlogs while the proxy keeps emitting events. `currentTurn` eventually clears (or doesn't), JSONL never lands. The ghost on disk is the only record of the turn.
2. **Crash + restart.** cc-shell exited mid-turn. Semantic state was in-memory and is gone. JSONL has a partial transcript that ends before the in-flight turn. The ghost log on disk preserves what the proxy saw; on resume it surfaces the lost partial turn.
2. **Crash + restart.** Agent Code exited mid-turn. Semantic state was in-memory and is gone. JSONL has a partial transcript that ends before the in-flight turn. The ghost log on disk preserves what the proxy saw; on resume it surfaces the lost partial turn.

Both reduce to the same condition: **proxy state is past the JSONL tail with no recovery in sight.** The render predicate detects this structurally.

Expand Down Expand Up @@ -121,8 +121,8 @@ The whole subsystem reads in one direction — semantic events flow in, the rend

### Components

- **atp ghost primitives** — `packages/agent-transcript-parser/src/ghost.ts`. Pure library: `createGhost`, `updateGhost`, `supersedeGhost`, `orphanGhost`, `reduceGhostLog`, `reduceGhostLogSansSuperseded`, `mergeWithUpstream`. No IO. Reusable outside cc-shell.
- **cc-shell renderer reducer** — `src/renderer/src/workspace/ghosts.ts`. Bridges semantic events to atp primitives: `ghostsFromSemanticTurn`, `reconcileUpstream`, `orphanStale`, `gcSupersededGhosts`, `ghostsToPersist`. Reference-stable on no-op.
- **atp ghost primitives** — `packages/agent-transcript-parser/src/ghost.ts`. Pure library: `createGhost`, `updateGhost`, `supersedeGhost`, `orphanGhost`, `reduceGhostLog`, `reduceGhostLogSansSuperseded`, `mergeWithUpstream`. No IO. Reusable outside Agent Code.
- **Agent Code renderer reducer** — `src/renderer/src/workspace/ghosts.ts`. Bridges semantic events to atp primitives: `ghostsFromSemanticTurn`, `reconcileUpstream`, `orphanStale`, `gcSupersededGhosts`, `ghostsToPersist`. Reference-stable on no-op.
- **render predicate** — `src/renderer/src/workspace/mergedEntries.ts`. The five-rule selector. Source of truth for "does this ghost surface in the feed."
- **IPC wiring** — `src/renderer/src/workspace/hook/ipc/useIpcSubscriptions.ts`. The orchestration layer: mint on semantic, reconcile on JSONL, sweep orphans on a 1s timer, stamp `lastJsonlEntryAt` from JSONL bursts, persist diffs.
- **bootstrap on resume** — `src/renderer/src/workspace/hook/actions/session.ts` (ghost log read + reconcile against loaded JSONL tail) and `src/renderer/src/workspace/hook/actions/initialHistory.ts` (stamping `lastJsonlEntryAt` from the loaded tail).
Expand Down Expand Up @@ -198,7 +198,7 @@ If you add a new code path that touches the ghost map, **uphold the contract**:

The ghost journal lives at `<userData>/ghost-logs/<sessionId>.ghost.jsonl`. One file per session. Append-only JSONL. Owned by the main process; the renderer fires-and-forgets `window.api.ghostAppend`.

Why a separate file and not the agent's own JSONL: cc-shell never writes into Claude Code's `~/.claude/projects/<proj>/<sid>.jsonl` or Codex's rollout file. Those belong to the agent and are actively written by its batched queue; two writers on the same file is a torn-line / lost-write disaster. Ghosts are also a cc-shell-internal concern — no external tool needs them.
Why a separate file and not the agent's own JSONL: Agent Code never writes into Claude Code's `~/.claude/projects/<proj>/<sid>.jsonl` or Codex's rollout file. Those belong to the agent and are actively written by its batched queue; two writers on the same file is a torn-line / lost-write disaster. Ghosts are also an Agent Code-internal concern — no external tool needs them.

Why batched at 100 ms: matches Claude Code's own transcript batch interval (`FLUSH_INTERVAL_MS` in `claude-code-src/full/utils/sessionStorage.ts`). Per-entry fsync during streaming would be tens of writes per second across every active pane. The trade-off — up to 100 ms of data loss on hard crash — is acceptable because ghost is provisional by definition and the agent's own JSONL survives independently.

Expand Down
2 changes: 1 addition & 1 deletion docs/plans_and_ideas/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

This document is a placeholder for ideas, plans, and possible improvements we may want to implement in the future.

It will be used to capture early concepts, feature directions, experiments, and other notes that can help guide future work on `cc-shell`.
It will be used to capture early concepts, feature directions, experiments, and other notes that can help guide future work on Agent Code.
4 changes: 2 additions & 2 deletions electron-builder.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
appId: com.agentstudiocode.app
productName: Agent Studio Code
appId: com.agentcode.app
productName: Agent Code
artifactName: "${productName}-${version}-${arch}.${ext}"
directories:
output: release
Expand Down
4 changes: 2 additions & 2 deletions electron.vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const headlessAlias = [
{ find: /^agent-transcript-parser\/(.+)$/, replacement: `${resolve(__dirname, 'packages/agent-transcript-parser/src')}/$1` },
{ find: 'agent-transcript-parser', replacement: resolve(__dirname, 'packages/agent-transcript-parser/src/index.ts') },
// `agent-voice-dictation` is a git submodule like the other local packages,
// so cc-shell must compile it from source. Relying on `dist` would make a
// so Agent Code must compile it from source. Relying on `dist` would make a
// fresh clone fail unless someone remembered to build the submodule first,
// and that hidden ordering dependency is exactly what the packages/ layout
// is meant to avoid.
Expand Down Expand Up @@ -56,7 +56,7 @@ function copyMainRuntimeResourcesPlugin(): Plugin {
}

return {
name: 'cc-shell-copy-main-runtime-resources',
name: 'agent-code-copy-main-runtime-resources',
apply: 'build',
async closeBundle() {
// WHY this lives in the Vite main build instead of only in
Expand Down
2 changes: 1 addition & 1 deletion issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ The order should be:

### Problem

Claude supports pasting images into input. `cc-shell` should support that too.
Claude supports pasting images into input. Agent Code should support that too.

This should not just be a hidden transport feature. The UI should make the pasted image visible and obvious before send.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ let parts = binding
let requestedModifiers = Set(parts.filter { modifierNames.contains($0) })
let requestedKey = parts.last.flatMap { modifierNames.contains($0) ? nil : $0 }

// These names match cc-shell's stored binding vocabulary. They are intentionally
// These names match Agent Code's stored binding vocabulary. They are intentionally
// physical-ish key names, not localized glyphs: a dictation trigger should not
// move just because the user has a Swedish/US/etc keyboard layout selected.
let keyCodes: [String: CGKeyCode] = [
Expand Down Expand Up @@ -76,13 +76,16 @@ func emit(_ type: String, _ extra: String = "") {
// helper saw Fn at all, but it now floods the terminal at every Cmd press
// and buries the dictation logs the user actually cares about. Keep the
// function so the call sites still compile, but make it a no-op unless
// CC_SHELL_HOTKEY_HELPER_DEBUG is set in the environment. Re-enable by
// running `CC_SHELL_HOTKEY_HELPER_DEBUG=1 npm run dev` if you ever need
// the raw modifier stream again.
let helperDebugEnabled = ProcessInfo.processInfo.environment["CC_SHELL_HOTKEY_HELPER_DEBUG"] == "1"
// AGENT_CODE_HOTKEY_HELPER_DEBUG is set in the environment. Re-enable by
// running `AGENT_CODE_HOTKEY_HELPER_DEBUG=1 npm run dev` if you ever need
// the raw modifier stream again. Keep the old CC_SHELL_* flag as a
// compatibility fallback for local scripts people may already have.
let helperDebugEnabled =
ProcessInfo.processInfo.environment["AGENT_CODE_HOTKEY_HELPER_DEBUG"] == "1" ||
ProcessInfo.processInfo.environment["CC_SHELL_HOTKEY_HELPER_DEBUG"] == "1"
func debug(_ message: String) {
if !helperDebugEnabled { return }
fputs("[cc-shell-hotkey-helper-debug] \(message)\n", stderr)
fputs("[agent-code-hotkey-helper-debug] \(message)\n", stderr)
fflush(stderr)
}

Expand All @@ -103,20 +106,20 @@ func changedModifierName(_ event: CGEvent) -> String? {
}

if binding.isEmpty {
fputs("[cc-shell-hotkey-helper] empty binding\n", stderr)
fputs("[agent-code-hotkey-helper] empty binding\n", stderr)
exit(64)
}

debug("boot binding=\(binding) requestedModifiers=\(requestedModifiers.sorted().joined(separator: "+")) requestedKey=\(requestedKey ?? "nil")")

if requestedKey != nil && requestedKeyCode == nil {
fputs("[cc-shell-hotkey-helper] unsupported key in binding: \(binding)\n", stderr)
fputs("[agent-code-hotkey-helper] unsupported key in binding: \(binding)\n", stderr)
exit(65)
}

let promptOptions = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true] as CFDictionary
if !AXIsProcessTrustedWithOptions(promptOptions) {
fputs("[cc-shell-hotkey-helper] accessibility permission is required\n", stderr)
fputs("[agent-code-hotkey-helper] accessibility permission is required\n", stderr)
}

let callback: CGEventTapCallBack = { _, type, event, _ in
Expand Down Expand Up @@ -194,7 +197,7 @@ guard let tap = CGEvent.tapCreate(
callback: callback,
userInfo: nil
) else {
fputs("[cc-shell-hotkey-helper] failed to create event tap\n", stderr)
fputs("[agent-code-hotkey-helper] failed to create event tap\n", stderr)
exit(66)
}

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "cc-shell",
"name": "agent-code",
"version": "0.0.2-beta.1",
"description": "Agent Studio Code desktop app",
"description": "Agent Code desktop app",
"main": "out/main/index.js",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/agent-transcript-parser
Submodule agent-transcript-parser updated from 5b6e1e to d0214f
Loading