Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
76338c5
Add CI workflow and local test runner
timvisher-dd Mar 15, 2026
d5b6d5b
Add agent-shell-alert: desktop notifications via OSC and macOS native
timvisher-dd Mar 14, 2026
7d45fbc
Add per-shell debug logging infrastructure
timvisher-dd Mar 14, 2026
886f21a
Add idle notification on prompt-waiting-for-input
timvisher-dd Mar 14, 2026
021807a
Add soft-fork README header with features list
timvisher-dd Mar 15, 2026
fbb25dc
Add regression tests for shell buffer selection ordering
timvisher-dd Feb 26, 2026
cc9ab0e
Add CI check that README.org is updated when code changes
timvisher-dd Mar 15, 2026
05ab3f0
Backfill PR #3 entry in README.org features list
timvisher-dd Mar 15, 2026
b07a394
Add usage tests and defend against ACP used > size bug
timvisher-dd Mar 11, 2026
7f85cf4
Add PR #5 entry to README.org features list
timvisher-dd Mar 15, 2026
ba9cb1e
Add README update check and fix acp_root error message in bin/test
timvisher-dd Mar 15, 2026
43dceaa
Add development workflow section to CLAUDE.md
timvisher-dd Mar 15, 2026
ebdba1d
Add PR #6 entry to README.org features list
timvisher-dd Mar 15, 2026
83a1ce8
Merge remote-tracking branch 'upstream/main'
timvisher-dd Mar 18, 2026
fdec6e8
Merge upstream/main into main
timvisher-dd Mar 18, 2026
cfd38fc
Refactor idle-notification in terms of emit-event system
timvisher-dd Mar 18, 2026
215f19a
Exit early from bin/test when byte-compilation or tests fail
timvisher-dd Mar 18, 2026
a45a08b
Add agent config symlinks for multi-IDE support
timvisher-dd Mar 20, 2026
f3eab31
Add CI workflow and local test runner
timvisher-dd Mar 20, 2026
d51d87e
Fix keymap quoting, test buffer-local bindings, and byte-compiler war…
timvisher-dd Mar 20, 2026
9d4ef02
Add runtime buffer invariants library
timvisher-dd Mar 20, 2026
331bb41
Add ACP meta helpers for toolResponse and terminal_output extraction
timvisher-dd Mar 20, 2026
4e5481f
Add streaming tool output handler with dedup
timvisher-dd Mar 20, 2026
1c5cea9
Integrate streaming dedup, insert-cursor, and process-mark preservation
timvisher-dd Mar 20, 2026
cb357ac
Update documentation for streaming dedup and live-validate workflow
timvisher-dd Mar 20, 2026
8635cb9
Update Claude Code icon
xenodium Mar 19, 2026
e4d65f4
Fixing auth-source-pass-get usage in README #434
xenodium Mar 19, 2026
4e1bc96
Try to include file name in permission title if missing #415
xenodium Mar 19, 2026
314b2b4
Adds agent-shell-mock-agent.el (needs mock-acp binary installed)
xenodium Mar 19, 2026
a0044ec
Adding experimental incoming session/pushPrompt
xenodium Mar 19, 2026
0710b49
Disable image pasting when running in tui #435
xenodium Mar 19, 2026
4e6ddad
Renaming experimental session/pushPrompt to session/push
xenodium Mar 20, 2026
a24ebb9
Adding more to CONTRIBUTING.org
xenodium Mar 20, 2026
4892364
Reject session/push requests when busy
xenodium Mar 20, 2026
3954508
Show activity indicator while receiving push and ignore out of bound …
xenodium Mar 21, 2026
1500196
Adding https://github.com/zackattackz/agent-shell-notifications to RE…
xenodium Mar 21, 2026
6f3ed77
Adds agent-shell-new-downloads-shell and agent-shell-new-temp-shell
xenodium Mar 22, 2026
307dce6
Add related project `agent-circus` to README.org
rpoisel Mar 22, 2026
28f1fb7
Make id more evident for available models and modes #452
xenodium Mar 24, 2026
0d639cc
Ensure that viewport compiles
martenlienen Mar 24, 2026
184b4c7
Use project-name instead of default-directory in header
bcc32 Mar 23, 2026
07db3a2
Prefer cache directory over tmp for caching
martenlienen Mar 25, 2026
a334503
Fix for structured input from toolCall.rawInput.plan
timfel Mar 20, 2026
7c40d53
Make agent-shell--format-plan more forgiving #438
xenodium Mar 25, 2026
12023b9
Enable expanding region/context text for editing #459
xenodium Mar 25, 2026
2fbe9f7
Fixes #455: unhandled method returns an error, unblocking client
0x6362 Mar 25, 2026
0093e35
Text header/modeline improvements #448
xenodium Mar 25, 2026
25a6178
Fixing checkdoc warning
xenodium Mar 25, 2026
313c0bb
Ensure button border does not leak into subsequently inserted text
xenodium Mar 25, 2026
b94cd0c
Add wl-paste as a Wayland image handler
martenlienen Mar 25, 2026
ea45407
Fix restart using wrong default-directory
zackattackz Mar 24, 2026
b13a9e8
Add documentation about the AOuth Anthropic authentication
chemtov Feb 26, 2026
2a78524
Fix header text invisible when font-get :size returns 0
Mar 25, 2026
8fa5b08
Replacing or + when-let* with if-let* #463
xenodium Mar 25, 2026
77e747b
Fixes refocus after diff regression #466
xenodium Mar 26, 2026
a8dca5d
Do not create a file if no image in Wayland clipboard
martenlienen Mar 26, 2026
6256877
Adding README entry for slash commands
xenodium Mar 26, 2026
3250af0
Shortening some agent names
xenodium Mar 27, 2026
f6150b6
Display key bindings in menu tooltips #448
xenodium Mar 27, 2026
f600ce8
Adding agent-shell-bookmark to related packages section
xenodium Mar 27, 2026
ed5d26a
Caching project files completions for improved performance
Gleek Mar 27, 2026
2f51417
Handle non-text content in user_message_chunk during session load
Gleek Mar 29, 2026
1af38c5
Fall back to "unknown" when type is not known #477
xenodium Mar 29, 2026
bcf36bb
Fix restart test to work in batch mode
timvisher-dd Mar 31, 2026
95c8c17
Fix extra closing paren in permission-title execute test
timvisher-dd Mar 31, 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
68 changes: 68 additions & 0 deletions .agents/commands/live-validate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Live validation of agent-shell rendering

Run a live agent-shell session in batch mode and verify the buffer output.
This exercises the full rendering pipeline with real ACP traffic — the only
way to catch ordering, marker, and streaming bugs that unit tests miss.

## Prerequisites

- `ANTHROPIC_API_KEY` must be available (via `op run` / 1Password)
- `timvisher_emacs_agent_shell` must be on PATH
- Dependencies (acp.el-plus, shell-maker) in sibling worktrees or
overridden via env vars

## How to run

```bash
cd "$(git rev-parse --show-toplevel)"
timvisher_agent_shell_checkout=. \
timvisher_emacs_agent_shell claude --batch \
1>/tmp/agent-shell-live-stdout.log \
2>/tmp/agent-shell-live-stderr.log
```

Stderr shows heartbeat lines every 30 seconds. Stdout contains the
full buffer dump once the agent turn completes.

## What to check in the output

1. **Fragment ordering**: tool call drawers should appear in
chronological order (the order the agent invoked them), not
reversed. Look for `▶` lines — their sequence should match the
logical execution order.

2. **No duplicate content**: each tool call output should appear
exactly once. Watch for repeated blocks of identical text.

3. **Prompt position**: the prompt line (`agent-shell>`) should
appear at the very end of the buffer, after all fragments.

4. **Notices placement**: `[hook-trace]` and other notice lines
should appear in a `Notices` section, not interleaved with tool
call fragments.

## Enabling invariant checking

To run with runtime invariant assertions (catches corruption as it
happens rather than after the fact):

```elisp
;; Add to your init or eval before the session starts:
(setq agent-shell-invariants-enabled t)
```

When an invariant fires, a `*agent-shell invariant*` buffer pops up
with a debug bundle and recommended analysis prompt.

## Quick validation one-liner

```bash
cd "$(git rev-parse --show-toplevel)" && \
timvisher_agent_shell_checkout=. \
timvisher_emacs_agent_shell claude --batch \
1>/tmp/agent-shell-live.log 2>&1 && \
grep -n '▶' /tmp/agent-shell-live.log | head -20
```

If the `▶` lines are in logical order and the exit code is 0, the
rendering pipeline is healthy.
1 change: 1 addition & 0 deletions .claude
1 change: 1 addition & 0 deletions .codex
1 change: 1 addition & 0 deletions .gemini
176 changes: 176 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
name: CI

on:
push:
branches: [main, dev]
pull_request:
branches: [main]

jobs:
readme-updated:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check README.org updated when code changes
run: |
base="${{ github.event.pull_request.base.sha }}"
head="${{ github.event.pull_request.head.sha }}"
changed_files=$(git diff --name-only "$base" "$head")

has_code_changes=false
for f in $changed_files; do
case "$f" in
*.el|tests/*) has_code_changes=true; break ;;
esac
done

if "$has_code_changes"; then
if ! echo "$changed_files" | grep -q '^README\.org$'; then
echo "::error::Code or test files changed but README.org was not updated."
echo "Please update the soft-fork features list in README.org."
exit 1
fi
fi

agent-symlinks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Verify agent config symlinks
run: |
ok=true
for dir in .claude .codex .gemini; do
target=$(readlink "${dir}" 2>/dev/null)
if [[ "${target}" != ".agents" ]]; then
echo "::error::${dir} should symlink to .agents but points to '${target:-<missing>}'"
ok=false
fi
done
for md in CLAUDE.md CODEX.md GEMINI.md; do
target=$(readlink "${md}" 2>/dev/null)
if [[ "${target}" != "AGENTS.md" ]]; then
echo "::error::${md} should symlink to AGENTS.md but points to '${target:-<missing>}'"
ok=false
fi
done
if ! [[ -d .agents/commands ]]; then
echo "::error::.agents/commands/ directory missing"
ok=false
fi
if [[ "${ok}" != "true" ]]; then
exit 1
fi
echo "All agent config symlinks verified."

dependency-dag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Verify require graph is a DAG (no cycles)
run: |
# Build the set of project-internal modules from *.el filenames.
declare -A project_modules
for f in *.el; do
mod="${f%.el}"
project_modules["${mod}"]=1
done

# Parse (require 'foo) from each file and build an adjacency list.
# Only track edges where both ends are project-internal.
declare -A edges # edges["a"]="b c" means a requires b and c
for f in *.el; do
mod="${f%.el}"
deps=""
while IFS= read -r dep; do
if [[ -n "${project_modules[$dep]+x}" ]]; then
deps="${deps} ${dep}"
fi
done < <(sed -n "s/^.*(require '\\([a-zA-Z0-9_-]*\\)).*/\\1/p" "$f")
edges["${mod}"]="${deps}"
done

# DFS cycle detection.
declare -A color # white=unvisited, gray=in-stack, black=done
found_cycle=""
cycle_path=""

dfs() {
local node="$1"
local path="$2"
color["${node}"]="gray"
for neighbor in ${edges["${node}"]}; do
if [[ "${color[$neighbor]:-white}" == "gray" ]]; then
found_cycle=1
cycle_path="${path} -> ${neighbor}"
return
fi
if [[ "${color[$neighbor]:-white}" == "white" ]]; then
dfs "${neighbor}" "${path} -> ${neighbor}"
if [[ -n "${found_cycle}" ]]; then
return
fi
fi
done
color["${node}"]="black"
}

for mod in "${!project_modules[@]}"; do
if [[ "${color[$mod]:-white}" == "white" ]]; then
dfs "${mod}" "${mod}"
if [[ -n "${found_cycle}" ]]; then
echo "::error::Dependency cycle detected: ${cycle_path}"
exit 1
fi
fi
done
echo "Dependency graph is a DAG — no cycles found."

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/checkout@v4
with:
repository: timvisher-dd/acp.el-plus
path: deps/acp.el

- uses: actions/checkout@v4
with:
repository: xenodium/shell-maker
path: deps/shell-maker

- uses: purcell/setup-emacs@master
with:
version: 29.4

- name: Remove stale .elc files
run: find . deps -follow -name '*.elc' -print0 | xargs -0 rm -f

- name: Byte-compile
run: |
compile_files=()
for f in *.el; do
case "$f" in x.*|y.*|z.*) ;; *) compile_files+=("$f") ;; esac
done
emacs -Q --batch \
-L . -L deps/acp.el -L deps/shell-maker \
-f batch-byte-compile \
"${compile_files[@]}"

- name: Run ERT tests
run: |
test_args=()
for f in tests/*-tests.el; do
test_args+=(-l "$f")
done
emacs -Q --batch \
-L . -L deps/acp.el -L deps/shell-maker -L tests \
"${test_args[@]}" \
-f ert-run-tests-batch-and-exit
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.agent-shell/
/deps/

*.elc
22 changes: 22 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,25 @@ When contributing:
## Contributing

This is an Emacs Lisp project. See [CONTRIBUTING.org](CONTRIBUTING.org) for style guidelines, code checks, and testing. Please adhere to these guidelines.

## Development workflow

When adding or changing features:

1. **Run `bin/test`.** Set `acp_root` and `shell_maker_root` if the
deps aren't in sibling worktrees. This runs byte-compilation, ERT
tests, dependency DAG check, and checks that `README.org` was
updated when code changed.
2. **Keep the README features list current.** The "Features on top of
agent-shell" section in `README.org` must be updated whenever code
changes land. Both `bin/test` and CI enforce this — changes to `.el`
or `tests/` files without a corresponding `README.org` update will
fail.
3. **Live-validate rendering changes.** For changes to the rendering
pipeline (fragment insertion, streaming, markers, UI), run a live
batch session to verify fragment ordering and buffer integrity.
See `.agents/commands/live-validate.md` for details. The key command:
```bash
timvisher_agent_shell_checkout=. timvisher_emacs_agent_shell claude --batch \
1>/tmp/agent-shell-live.log 2>&1
```
1 change: 1 addition & 0 deletions CODEX.md
31 changes: 31 additions & 0 deletions CONTRIBUTING.org
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,20 @@ Overall, try to flatten things. Look out for unnecessarily nested blocks and fla
buffer)
#+end_src

Similarly, flatten =when-let= + nested =when= by using boolean guard clauses as bindings in =when-let=.

#+begin_src emacs-lisp :lexical no
;; Avoid
(when-let ((filename (file-name-nondirectory filepath)))
(when (not (string-empty-p filename))
(do-something filename)))

;; Prefer (use boolean binding as guard clause)
(when-let ((filename (file-name-nondirectory filepath))
((not (string-empty-p filename))))
(do-something filename))
#+end_src

** Prefer =let= and =when-let= over =let*= and =when-let*=

Only use the =*= variants when bindings depend on each other. LLMs tend to default to =let*= and =when-let*= even when there are no dependencies between bindings.
Expand Down Expand Up @@ -231,3 +245,20 @@ Tests live under the tests directory:
Opening any file under the =tests= directory will load the =agent-shell-run-all-tests= command.

Run tests with =M-x agent-shell-run-all-tests=.

*** From the command line

=bin/test= runs the full ERT suite in batch mode. By default it
expects =acp.el= and =shell-maker= to be checked out as sibling
worktrees (e.g. =…/acp.el/main= and =…/shell-maker/main= next to
=…/agent-shell/main=). Override the paths with environment variables
if your layout differs:

#+begin_src bash
acp_root=~/path/to/acp.el \
shell_maker_root=~/path/to/shell-maker \
bin/test
#+end_src

The script validates that both dependencies are readable and exits
with a descriptive error if either is missing.
Loading