Compare commits

..

4 Commits

Author SHA1 Message Date
didericis-claude c6e976fa7d docs(prd): mark commit-bottle-state PRD as Active
lint / lint (push) Failing after 1m43s
test / unit (pull_request) Successful in 33s
test / integration (pull_request) Successful in 19s
2026-06-22 22:29:33 -04:00
didericis-claude 66baaf1a80 feat(cli): add commit command to snapshot running bottle state
Adds `./cli.py commit [<slug>]` which runs `docker commit` on the
active agent container and stores the resulting image tag in per-bottle
state. The next `./cli.py resume <slug>` automatically boots from the
committed snapshot instead of rebuilding from the Dockerfile, preserving
all in-container state across restarts and migrations.

- bottle_state: add write_committed_image / read_committed_image helpers
- docker/util: add commit_container wrapper around `docker commit`
- docker/launch: check for a committed image before the Dockerfile build
  step; fall back to normal build if the image is absent from the daemon
- cli/commit: new command with interactive slug picker; errors clearly on
  non-Docker backends
- 50 new unit tests covering all paths

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 22:29:33 -04:00
Quality Badge Bot b5b7f15ef9 chore: update quality badges
- Pylint: 9.92/10
- Pyright: 0 errors

[skip ci]
2026-06-23 00:57:24 +00:00
didericis-claude 85e64b5134 feat: display agent name alongside label in terminal title and list output
test / unit (pull_request) Successful in 40s
test / integration (pull_request) Successful in 17s
lint / lint (push) Successful in 1m42s
test / unit (push) Successful in 41s
test / integration (push) Successful in 20s
Update Quality Badges / update-badges (push) Successful in 1m26s
When a label is set (e.g. "bob"), the display becomes "bob (claude-implementer)"
so the agent type is always visible. Affects all three backends (docker,
macos-container, smolmachines) and the `cli.py list active` output.

Closes #243
2026-06-23 00:28:16 +00:00
5 changed files with 5 additions and 5 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
# bot-bottle
[![test](https://gitea.dideric.is/didericis/bot-bottle/actions/workflows/test.yml/badge.svg?branch=main)](https://gitea.dideric.is/didericis/bot-bottle/actions?workflow=test.yml)
[![pylint](https://img.shields.io/badge/pylint-9.93%2F10-brightgreen)](https://github.com/PyCQA/pylint)
[![pylint](https://img.shields.io/badge/pylint-9.92%2F10-brightgreen)](https://github.com/PyCQA/pylint)
[![pyright](https://img.shields.io/badge/pyright-0%20errors-brightgreen)](https://github.com/microsoft/pyright)
**Problem:** Developer wants to run a coding agent without supervision, but they don't want a prompt injected or misbehaving agent wrecking their environment or exfiltrating sensitive data.
+1 -1
View File
@@ -187,7 +187,7 @@ def launch(
agent_command=plan.agent_command,
agent_prompt_mode=plan.agent_prompt_mode,
agent_provider_template=plan.agent_provider_template,
terminal_title=plan.spec.label or plan.spec.agent_name,
terminal_title=f"{plan.spec.label} ({plan.spec.agent_name})" if plan.spec.label else plan.spec.agent_name,
terminal_color=plan.spec.color,
agent_workdir=plan.workspace_plan.workdir,
)
+1 -1
View File
@@ -112,7 +112,7 @@ def launch(
agent_command=plan.agent_command,
agent_prompt_mode=plan.agent_prompt_mode,
agent_provider_template=plan.agent_provider_template,
terminal_title=plan.spec.label or plan.spec.agent_name,
terminal_title=f"{plan.spec.label} ({plan.spec.agent_name})" if plan.spec.label else plan.spec.agent_name,
terminal_color=plan.spec.color,
agent_workdir=plan.workspace_plan.workdir,
)
+1 -1
View File
@@ -104,7 +104,7 @@ def launch(
agent_command=plan.agent_command,
agent_prompt_mode=plan.agent_prompt_mode,
agent_provider_template=plan.agent_provider_template,
terminal_title=plan.spec.label or plan.spec.agent_name,
terminal_title=f"{plan.spec.label} ({plan.spec.agent_name})" if plan.spec.label else plan.spec.agent_name,
terminal_color=plan.spec.color,
agent_workdir=plan.workspace_plan.workdir,
)
+1 -1
View File
@@ -55,7 +55,7 @@ def cmd_list(argv: list[str]) -> int:
# Tab-separated keeps the format stable for shell pipelines.
for b in active:
services = ",".join(b.services) if b.services else "-"
display_name = b.label if b.label else b.agent_name
display_name = f"{b.label} ({b.agent_name})" if b.label else b.agent_name
colored_name = _ansi_label(display_name, b.color)
print(f"{b.backend_name}\t{b.slug}\t{colored_name}\t{services}")
return 0