Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e2de297
grand refactor prep
cohix Apr 30, 2026
a0ef884
Implement amux/work-item-0066
cohix Apr 30, 2026
8155217
update grand architecture work items
cohix May 1, 2026
8dd0d59
Implement amux/work-item-0067
cohix May 1, 2026
cffd37c
update grand arch work items
cohix May 1, 2026
c6b5826
Implement amux/work-item-0068
cohix May 1, 2026
9bb41d5
update work item 69
cohix May 1, 2026
f4cac38
update work item 69
cohix May 1, 2026
034d1a2
implement work item 69
cohix May 2, 2026
648c3f7
post- WI69 rework of plan
cohix May 2, 2026
4708627
Implement amux/work-item-0070
cohix May 3, 2026
fc8e843
work item 70 checkpoint
cohix May 3, 2026
9e100e6
firther WI70 tweaking
cohix May 3, 2026
1d9c5d0
fixes for work item 70
cohix May 3, 2026
72399b5
more WI70 fixes
cohix May 3, 2026
4b66396
more WI-70 fixes
cohix May 3, 2026
4a99fe3
More fixes for work item 70
cohix May 3, 2026
a905c66
pre-WI 71 updates
cohix May 4, 2026
a27cbc2
real final pre-71 fixes
cohix May 4, 2026
101f521
Implement amux/work-item-0071
cohix May 4, 2026
9f26450
TUI fixes and prep for WI 74
cohix May 6, 2026
e67f5e0
TUI fixes and workflow spike
cohix May 6, 2026
559f700
WIP: pre-worktree commit for amux/work-item-0072
cohix May 6, 2026
46da699
Implement work item 72
cohix May 7, 2026
5c48475
WIP: pre-worktree commit for amux/work-item-0074
cohix May 7, 2026
65fddb5
post-WI-74 merge
cohix May 8, 2026
347ee8f
WIP: pre-worktree commit for amux/work-item-0073
cohix May 8, 2026
6d3bb79
fixes for workflows and TUI
cohix May 8, 2026
4343ca6
Implement amux/work-item-0073
cohix May 8, 2026
c5f5b0f
TUI and engine fixes
cohix May 8, 2026
80bc966
simplify workflow engine
cohix May 9, 2026
71aa858
fixes for yolo, WCB, worktree merge
cohix May 9, 2026
dae4cb1
huge workflow engine rewrite
cohix May 10, 2026
9be3099
Implement amux/work-item-0075
cohix May 10, 2026
7eb98f1
fixes for WI77
cohix May 10, 2026
b9ddb1e
Implement amux/work-item-0078
cohix May 10, 2026
fc2d5b5
workflow control board tweaks
cohix May 10, 2026
9fe2ef6
merge work item 78 and resolve conflicts
cohix May 10, 2026
4349a19
misc and ports
cohix May 11, 2026
4bc70e9
fix status table in TUI
cohix May 11, 2026
45c4367
finally delete oldsrc
cohix May 11, 2026
a237a5e
fix CI
cohix May 11, 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
60 changes: 60 additions & 0 deletions .amux/Dockerfile.gemini
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
FROM amux-amux:latest

# Force root for installation: a base image may have switched to a non-root
# user, and apt/cp/install need write access to /usr/local, /etc, /root.
USER root

# Reset env vars so installer behavior does not depend on what the base set:
# - HOME drives where installers and tools write user-scoped files.
# - DEBIAN_FRONTEND avoids interactive apt prompts.
# - PATH prepends the agent baseline to whatever the base image set,
# so installer-resolved binaries cannot be shadowed by the base while
# useful base PATH additions (e.g. /usr/local/cargo/bin from
# Dockerfile.dev) stay visible inside the agent container.
ENV HOME=/root \
DEBIAN_FRONTEND=noninteractive \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
WORKDIR /root

# Strict shell for every RUN: -e fails fast, -o pipefail catches errors in
# `curl | bash` pipelines so a partial download cannot silently succeed.
SHELL ["/bin/bash", "-eo", "pipefail", "-c"]

# Override any inherited ENTRYPOINT/CMD so `docker run image <command> ...`
# behaves predictably regardless of how the base evolves.
ENTRYPOINT []
CMD ["/bin/bash"]

# ── Install agent binary ──────────────────────────────────────────────────────
# Wipe inherited apt state before updating in case the base left a broken
# sources.list or stale lock. Then install Node 20 and the agent npm package;
# nodesource defaults its npm prefix to /usr/local, so the binary lands in
# /usr/local/bin where the smoke test expects it.
RUN rm -rf /var/lib/apt/lists/* \
&& apt-get clean \
&& apt-get update \
&& apt-get install -y --no-install-recommends gnupg \
&& curl -fsSL --retry 5 --retry-delay 2 --retry-max-time 60 https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*

RUN npm install -g --prefix=/usr/local @google/gemini-cli

# ── amux user + workspace (idempotent against a base that already created it) ─
# Outer braces keep the && chain associated with the user-creation block,
# avoiding the `A || B && C && D` precedence trap that would otherwise skip
# `mkdir`/`chown` whenever the user already exists.
RUN { id -u amux >/dev/null 2>&1 \
|| useradd -m -s /bin/bash -d /home/amux amux 2>/dev/null \
|| useradd -s /bin/bash -d /home/amux amux ; } \
&& mkdir -p /workspace /home/amux \
&& chown -R amux:amux /workspace /home/amux

USER amux
ENV HOME=/home/amux \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
WORKDIR /workspace

# ── Smoke test: run as the runtime user so we verify the binary is on PATH and
# executable from the actual entrypoint context, not just for root. ───────────
RUN test -x "$(command -v gemini)"
70 changes: 70 additions & 0 deletions .amux/Dockerfile.maki
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
FROM amux-amux:latest

# Force root for installation: a base image may have switched to a non-root
# user, and apt/cp/install need write access to /usr/local, /etc, /root.
USER root

# Reset env vars so installer behavior does not depend on what the base set:
# - HOME drives where installers and tools write user-scoped files.
# - DEBIAN_FRONTEND avoids interactive apt prompts.
# - PATH prepends the agent baseline to whatever the base image set,
# so installer-resolved binaries cannot be shadowed by the base while
# useful base PATH additions (e.g. /usr/local/cargo/bin from
# Dockerfile.dev) stay visible inside the agent container.
ENV HOME=/root \
DEBIAN_FRONTEND=noninteractive \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
WORKDIR /root

# Strict shell for every RUN: -e fails fast, -o pipefail catches errors in
# `curl | bash` pipelines so a partial download cannot silently succeed.
SHELL ["/bin/bash", "-eo", "pipefail", "-c"]

# Override any inherited ENTRYPOINT/CMD so `docker run image <command> ...`
# behaves predictably regardless of how the base evolves.
ENTRYPOINT []
CMD ["/bin/bash"]

# ── Install agent binary ──────────────────────────────────────────────────────
# The maki installer drops a launcher under $HOME/.local/bin which may be a
# symlink into a deeper $HOME/.local/share path. So we:
# 1. Save the script to disk first so `--retry` can recover from transient
# curl failures without `curl ... | bash` muddling pipefail semantics.
# 2. Check the well-known launcher path directly before falling back to a
# wider find that includes symlinks and goes deep enough to reach the
# real binary.
# 3. Use `install` to copy through the symlink — it dereferences the source
# and produces a real binary at /usr/local/bin/maki.
RUN curl -fsSL --retry 5 --retry-delay 2 --retry-max-time 60 \
https://maki.sh/install.sh -o /tmp/maki-install.sh \
&& bash /tmp/maki-install.sh \
&& rm -f /tmp/maki-install.sh \
&& BIN="" \
&& if [ -e "$HOME/.local/bin/maki" ]; then BIN="$HOME/.local/bin/maki"; fi \
&& if [ -z "$BIN" ]; then BIN="$(command -v maki 2>/dev/null || true)"; fi \
&& if [ -z "$BIN" ]; then \
BIN="$(find / -maxdepth 8 \( -type f -o -type l \) -name maki -print -quit 2>/dev/null || true)"; \
fi \
&& if [ -z "$BIN" ]; then \
echo "ERROR: maki binary not found after installation" >&2; exit 1; \
fi \
&& if [ "$BIN" != /usr/local/bin/maki ]; then install -m 0755 "$BIN" /usr/local/bin/maki; fi

# ── amux user + workspace (idempotent against a base that already created it) ─
# Outer braces keep the && chain associated with the user-creation block,
# avoiding the `A || B && C && D` precedence trap that would otherwise skip
# `mkdir`/`chown` whenever the user already exists.
RUN { id -u amux >/dev/null 2>&1 \
|| useradd -m -s /bin/bash -d /home/amux amux 2>/dev/null \
|| useradd -s /bin/bash -d /home/amux amux ; } \
&& mkdir -p /workspace /home/amux \
&& chown -R amux:amux /workspace /home/amux

USER amux
ENV HOME=/home/amux \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
WORKDIR /workspace

# ── Smoke test: run as the runtime user so we verify the binary is on PATH and
# executable from the actual entrypoint context, not just for root. ───────────
RUN test -x "$(command -v maki)"
4 changes: 1 addition & 3 deletions .amux/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
{
"agent": "claude",
"envPassthrough": [
"OMLX_API_KEY"
]
"terminal_scrollback_lines": 7500
}
6 changes: 5 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,11 @@
"Bash(rm /tmp/symlink-probe/cargo /tmp/symlink-probe/rustc)",
"Bash(rmdir /tmp/symlink-probe)",
"Bash(./target/release/amux --version)",
"Bash(./target/release/amux --help)"
"Bash(./target/release/amux --help)",
"Bash(sudo chown *)",
"WebFetch(domain:google-gemini.github.io)",
"WebFetch(domain:developers.openai.com)",
"Bash(CARGO_TARGET_DIR=/tmp/amux-target cargo test)"
]
}
}
127 changes: 127 additions & 0 deletions .claude/skills/blog-post/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
---
name: blog-post
description: Write a blog post in the preferred style related to amux
---

# Skill: blog-post

## Description

Write a new blog post for amux in the established first-person, problem-driven style. Posts live in `docs/blog/` and are numbered sequentially.

## Body

### Step 1: Understand the topic

If the user has not specified a topic, ask them: "What should the blog post be about?" Accept a feature name, a release version, a theme, or a free-form description. Do not invent a topic.

If the user says "the latest release" or similar, run:

```bash
git log --oneline -10
ls aspec/work-items/ | sort -r | head -10
cat Cargo.toml | grep '^version'
```

Read the relevant work items in `aspec/work-items/` to understand what changed.

### Step 2: Read existing blog posts for style calibration

Read the two most recent posts in `docs/blog/` (highest-numbered files):

```bash
ls docs/blog/*.md | sort -r | head -3
```

Read at least two of them fully. Do not skim. You are calibrating voice, length, and structure — not extracting facts.

Also read `docs/blog/0001-announcement.md` if the topic is introductory or architectural.

### Step 3: Determine the next post number and slug

```bash
ls docs/blog/*.md | sort -r | head -1
```

Increment the four-digit prefix by one. Choose a short, lowercase, hyphenated slug that names the theme, not the release version (e.g. `grand-refactor`, `headless-remote`, `specs-and-status`). Do not use version numbers as slugs unless the post is a general announcement.

The filename is: `docs/blog/NNNN-slug.md`

### Step 4: Draft the post

Follow this structure exactly:

```markdown
# amux X.Y: Short title ← or a plain title if not release-tied

<one or two sentences — the problem or itch, not the solution>

---

```sh
# install or upgrade
curl -s https://prettysmart.dev/install/amux.sh | sh
```

---

<main body: 2–4 named sections using ## headers>

---

<one short paragraph: where things stand, what's next, or a frank admission>

---

Source and issues at [github.com/prettysmartdev/amux](https://github.com/prettysmartdev/amux). More at [prettysmart.dev](https://prettysmart.dev). Feedback and contributions welcome.
```

### Step 5: Apply the style rules

**Voice and tone**
- Write in first person ("I built this...", "I've been wanting...", "I decided to...").
- Open with the problem or friction point — never open with the solution.
- Explain *why* the feature or change matters before explaining *what* it does.
- Be direct. Use plain language. No hedging, no marketing copy.

**What to avoid**
- No buzzwords: "revolutionary", "game-changing", "seamless", "robust", "powerful", "exciting"
- No fluff openers: "In this post I will...", "I'm excited to announce...", "Today we're launching..."
- No long calls to action at the end — just the two-line pointer to GitHub and prettysmart.dev
- No passive voice when active voice works

**What to include**
- Shell examples with `sh` code blocks for any commands a reader would run
- Screenshot placeholders (e.g. `![TUI showing the new dialog](images/NNNN-slug-01.png)`) when a visual would help — do not attempt ASCII art
- The install snippet (`curl -s https://prettysmart.dev/install/amux.sh | sh`) in the first third of the post, inside a `---` fenced section
- Concrete "before vs. after" framing when the post is about a fix or refactor

**Length**
- Target 400–600 words in the body (not counting headers, code blocks, or the install snippet).
- If you exceed 600 words, you are over-explaining. Cut the section that reads most like documentation and link to `docs/usage.md` instead.

### Step 6: Write the file

Write the post to `docs/blog/NNNN-slug.md`. Do not create any other files.

Do not summarize what you wrote or list what sections you included. The user will read the file.

### Decision tree

```
Did the user specify a topic?
Yes → use it
No → ask before writing anything

Is the topic tied to a specific release version?
Yes → include "amux X.Y:" in the title
No → use a plain descriptive title

Does the topic involve new commands or flags?
Yes → include at least one shell code block demonstrating them
No → skip the install blurb if no new behavior exists for users to try
(but still include the install line if it's a release post)

Is the post longer than 600 words?
Yes → find the most documentation-like section and cut or shorten it
```
80 changes: 74 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ on:
branches: ["**"]

jobs:
test:
name: Run tests
fast:
name: Fast checks (lint, fmt, clippy, hermetic tests)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -17,6 +17,7 @@ jobs:
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.94.0"
components: rustfmt, clippy

- name: Cache cargo registry and build
uses: actions/cache@v4
Expand All @@ -25,9 +26,76 @@ jobs:
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
key: ${{ runner.os }}-cargo-fast-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
${{ runner.os }}-cargo-fast-

- name: Run tests
run: make test
- name: Architecture lint
run: make architecture-lint

- name: Format check
run: cargo fmt --check

- name: Clippy (deny warnings)
run: cargo clippy --all-targets -- -D warnings

- name: Hermetic tests
run: make test-fast

full-linux-docker:
name: Full tests with Docker (Linux)
runs-on: ubuntu-latest
needs: fast
steps:
- uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.94.0"

- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-full-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-full-

- name: Verify Docker is available
run: docker info

- name: Full test suite (real Docker, real git)
run: make test-full

build-macos:
name: Build smoke (macOS)
runs-on: macos-latest
needs: fast
steps:
- uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.94.0"

- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-mac-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-mac-

- name: Build release
run: cargo build --release

- name: Hermetic tests
run: make test-fast
7 changes: 6 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,10 @@ make test # run all tests
Work items live in `aspec/work-items/`. Use `aspec/work-items/0000-template.md` as the template for new work items.

After implementing a work item:
1. Review and update `docs/` to reflect the current state of the tool (comprehensive docs, not per-work-item)
1. Review and update `docs/` to reflect the current state of the tool
- **Documentation must be user-facing, NOT work-item-specific**
- Do not create "WI 0XYZ implementation guide" docs
- Instead, update existing user docs (e.g., `docs/08-headless-mode.md`) to describe current behavior
- If a new feature warrants a new doc file, create it as a user guide (e.g., `docs/10-new-feature.md`), not as implementation/architecture notes
- Implementation details, decisions, and technical notes belong in the work item spec or code comments, never in published docs
2. Follow the patterns, conventions, and architecture established in the `aspec/` spec
Loading
Loading