Skip to content

feat(terminal): add panopticon onboard β€” Claude-backed setup launcher#217

Draft
tildesrc wants to merge 42 commits into
mainfrom
panopticon/onboard-claude-launcher
Draft

feat(terminal): add panopticon onboard β€” Claude-backed setup launcher#217
tildesrc wants to merge 42 commits into
mainfrom
panopticon/onboard-claude-launcher

Conversation

@tildesrc

Copy link
Copy Markdown
Contributor

Adds a panopticon onboard subcommand that opens an interactive Claude Code session configured to guide a new user through first-time Panopticon setup β€” no multi-stage Python wizard, no prereq probing in code. The only requirement is a working claude install.

What it does

  • Composes a system-prompt addendum (WIZARD_CONTEXT) with a full setup guide: prereqs β†’ build β†’ auth β†’ start β†’ configure repo β†’ create first task β†’ troubleshooting β†’ what's next
  • Passes it via --append-system-prompt so Claude has the full context before the first user turn
  • Sends INITIAL_PROMPT as the first user message so Claude begins guiding immediately
  • Runs subprocess.run(["claude", "--append-system-prompt", ..., INITIAL_PROMPT]) β€” inherits the caller's TTY for a fully interactive session

Files

  • src/panopticon/terminal/onboard.py β€” WIZARD_CONTEXT, INITIAL_PROMPT, run_onboard() with injectable runner
  • src/panopticon/terminal/__main__.py β€” wires onboard subcommand
  • tests/test_onboard.py β€” 4 tests; no real claude invoked

See plan.md for the full design.

πŸ€– Generated with Claude Code

Panopticon Agent and others added 15 commits June 29, 2026 00:55
Adds a `panopticon onboard` subcommand that opens an interactive Claude
Code session with the full first-time setup guide baked into the system
prompt, so new users get a guided walkthrough without running any manual
curl/make commands themselves. The only requirement is a working `claude`
install.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`scripts/onboard` is a self-contained bash script (works on Linux and
macOS) that opens a Claude Code session with the full Panopticon setup
guide baked in via --append-system-prompt. The only requirement is a
working `claude` install in PATH β€” no Python, no make, nothing else.

Removes the earlier Python implementation from terminal/__main__.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Stage 5: steer towards GitHub or purely-local repos; recommend a
  small coding task as the test; explain git_url accepts local paths
- Stage 6: recommend github-self-reviewed (full planning→PR→merge
  lifecycle, self-review) over spike; note spike as fallback for
  local-only repos
- Stage 7: explain that first attach lands in PLANNING mode and the
  user must give a prompt; add an example planning prompt; explain
  how to view plan.md via the dashboard artifact browser (a β†’ e)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- scripts/onboard writes ~/.panopticon/.onboarded sentinel at startup
- dashboard skips the first-run repo-screen auto-open when that sentinel
  exists (the onboard flow already created the repo)
- WIZARD_CONTEXT instructs Claude to collect repo/task details from the
  user and run the curl calls itself (stages 5 and 6)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All stage headings now read "Stage X of 7"; sub-step lists in Stage 3
(auth, 5 steps), Stage 5 (repo info, 4 items), and Stage 7 (view plan,
3 steps) are annotated with their totals. Added a preamble instruction
telling Claude to always announce progress with the full count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds panopticon.env.template to the repo root with placeholder values
for CLAUDE_CODE_OAUTH_TOKEN and (commented) GH_TOKEN. Stage 3 of the
wizard now instructs Claude to copy the template to the chosen env-file
path if the file does not already exist (never clobbers), then tells the
user to fill in real values in their editor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ific editor

Added a preamble rule forbidding Claude from naming any specific editor
(nano, vim, etc.); softened step 4 of 5 and plan-viewing step 3 of 3
to say "preferred editor" / "default handler" instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Stage 4 now explicitly tells Claude not to run make start itself β€”
instead ask the user to run it, then verify via /healthz.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Stage 5 no longer asks the user for a short repo ID (derived from the
git URL) or the default branch (assumed to be main, with a mention to
the user). Ask list drops from 4 items to 2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…se failures

Stage 6 now instructs Claude to poll container_status until live (~3 min
budget), then diagnose failed/stuck states: failed+lifecycle_detail,
stuck-building, stuck-claiming/queued.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
macOS ships bash 3.2, which has a bug where a heredoc nested inside $()
fails to parse. Switch to the compatible read -r -d '' pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Stage 2 now directs the onboarding assistant to run the build commands
itself; the user is only asked to run make start (which opens the dashboard).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread panopticon.env.template Outdated
Comment on lines +1 to +6
# Panopticon repo env-file template
# Copy this to a path OUTSIDE the repo, e.g.:
# cp panopticon.env.template ~/.panopticon/secrets/<repo-name>.env
# chmod 0600 ~/.panopticon/secrets/<repo-name>.env
# Then fill in the real values and never commit them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not include these instructions in this file itself. It is confusing to the user.

Panopticon Agent and others added 14 commits June 29, 2026 20:15
…late file

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SQLAlchemy's async engine requires greenlet, but SQLAlchemy only declares it
for select platform_machine values (Linux aarch64, x86_64, etc.) and omits
macOS arm64. uv therefore skipped greenlet on Apple Silicon, so the task
service crashed on startup with 'No module named greenlet'. Declare greenlet
as an explicit, marker-free project dependency so every platform installs it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(ci): add smoke test for make start on Linux and macOS

Adds a `host` Makefile target that starts the task service and
session-service runner in background tmux sessions without the
interactive console. `make start` is refactored to depend on `host`
(eliminating the duplicated tmux session setup), then runs
`panopticon console`. A new `smoke.yml` GHA workflow exercises
`make host` on ubuntu-latest and macos-latest, polling the service
health check and asserting both tmux sessions are alive.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(ci): capture service logs and increase health-check timeout for macOS

Log task-service and session-service output via `tee` in `make host`
so crash output survives tmux session death. Dump log files alongside
pane captures in the failure handler. Increase health-check poll from
30 s to 60 s to give macOS more startup time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(deps): declare sqlalchemy[asyncio] to install greenlet on macOS arm64

SQLAlchemy's base dependency on greenlet is conditional on platform_machine,
which includes aarch64 (Linux ARM) but not arm64 (macOS ARM). The asyncio
extra pins greenlet unconditionally, so switching to sqlalchemy[asyncio]
fixes the startup crash on macos-latest GitHub Actions runners (Apple Silicon).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon <panopticon@local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(dashboard): add fartbarf easter egg

Typing f-a-r-t-b-a-r-f in the dashboard opens a surprise URL. The URL
is stored as a base64 blob and the constants use terse non-descriptive
names so the purpose isn't obvious on inspection. Fully undocumented β€”
absent from HOTKEYS and HelpScreen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(dashboard): encode _KS as base64 like _KU

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(dashboard): trigger easter egg via FARTBARF task memo

Replace the key-sequence trigger with a memo-intercept: typing FARTBARF
as the task memo (case-insensitive) opens the URL instead of creating a
task. The comparison string is also base64-encoded so neither the
trigger word nor the destination are readable in plain text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(dashboard): inline _KU at the call site

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(dashboard): extract memo check into _apply_memo_filter

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(dashboard): remove easter egg tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon Agent <agent@panopticon.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: add macOS developer setup guide

Covers Docker Desktop vs Docker Engine distinction, tmux requirement,
what runs on the macOS host vs inside Linux containers, quick start,
and known macOS limitations (--network host, Docker-in-Docker on Apple Silicon).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: remove confusing make serve line from what-runs-where diagram

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon Agent <panopticon@example.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
When CI passes (EXIT:0) but the PR already has auto-merge enabled
(autoMergeRequest non-null), babysit-ci now invokes /babysit-merge
instead of stopping β€” so the task's turn stays on the agent and the
merge queue is shepherded without requiring a user hand-off.

Co-authored-by: Panopticon Agent <agent@panopticon.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(workflows): per-repo workflow filtering via opt_in flag

Each workflow declares opt_in = True (hidden by default, must be
explicitly enabled per repo) or False (shown for all repos unless
disabled). Repos carry enabled_workflows and disabled_workflows lists
that override the defaults.

- GET /repos/{repo_id}/workflows returns the filtered list for a repo
- POST /tasks now validates the chosen workflow is visible for the repo
- Dashboard fetches the repo-scoped list after the user picks a repo
- github-peer-reviewed and github-self-reviewed are now opt_in = True
- New Alembic migration adds the two JSON columns to the repos table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(dashboard): workflow fields in repo form (enabled/disabled, comma-separated)

The repo create/edit form (`g` β†’ `e`) now shows two text inputs for
enabled_workflows and disabled_workflows (comma-separated workflow names).
Pre-populated from the stored repo in edit mode; values are parsed back
into lists on submit and sent via the existing PATCH/POST API.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon Agent <agent@panopticon>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add `verbose: bool = False` to `CommandRunner`, `_subprocess_run`,
`ImageBuilder.build()`, and `ImageBuilder.build_base_if_missing()`.
When verbose, docker build stdout/stderr inherit the runner process's
streams instead of being captured, so the output is visible live in
the runner's tmux pane (reachable via `u` from the dashboard).

The spawner passes `verbose=True` for both base-image and composed-image
builds, and adds `_log.info()` calls at each lifecycle phase (claiming β†’
preparing β†’ building β†’ starting β†’ awaiting β†’ failed). `host.main()` now
calls `logging.basicConfig(level=INFO)` so those messages actually appear.

Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(dashboard): add auto-submit checkbox to memo modal

The memo modal now includes a Space-toggled checkbox that controls
whether the memo is submitted automatically (routed as `initial_prompt`
β†’ delivered as a positional arg to `claude`, no manual Enter needed) or
pasted unsent (original behaviour, user presses Enter to begin).

Workflows declare their default via `auto_submit_memo: ClassVar[bool]`.
`github-self-reviewed`, `github-peer-reviewed`, and
`local-git-self-reviewed` default to `True` (task description is
sufficient context to start immediately); `spike` and `orchestrator`
default to `False` (free-form tasks benefit from the user confirming
or editing the prompt first).

The flag is exposed through `GET /workflows` as `auto_submit_memo` and
consumed by the dashboard when the workflow picker returns a selection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(dashboard): rename checkbox label to "Use as initial prompt"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(dashboard): store memo on task even when auto-submitted as initial_prompt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(dashboard): rename checkbox label to "Submit as initial prompt"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon <panopticon@local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…or (#231)

* feat(dashboard): fade terminal task rows instead of drawing a separator

Terminal (COMPLETE/DROPPED) tasks now render in dim styling on all columns
rather than being visually separated by a grey divider row. The separator row,
its key sentinel, and the arrow-key skip logic for it are all removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(dashboard): dim terminal tasks by state, not section membership

A governed task that is COMPLETE/DROPPED but whose governor is still active
lives in the active section, so the old section-based `terminal` flag missed
it. Switch to checking `task["state"] in TERMINAL_LABELS` directly in
`_add_row` so every terminal-state task is faded regardless of which section
it was placed in.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon Agent <agent@panopticon.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…dpoint (#235)

list_workflow_infos_for_repo omitted auto_submit_memo, causing the dashboard
to always fall back to False for the memo checkbox regardless of the workflow's
actual setting. Also updates the return type annotation in service.py and api.py.

Co-authored-by: Panopticon <panopticon@example.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Shows "agent N/M" in the bottom-right corner of the footer where N is the
number of active tasks currently on the agent's turn and M is the total
active (non-terminal) tasks. The counter reflects the global system state
even when a search filter is applied.

Subclasses Footer as _StatusFooter so the counter Static survives Footer's
recompose cycles (triggered by _bindings_ready); action_refresh uses a
query() guard to tolerate the brief window before Footer first composes.

Co-authored-by: Panopticon Agent <agent@panopticon.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The prefill mechanism (watching for ESC[?2004h via pipe-pane then pasting
the memo via paste-buffer) is replaced by passing the memo as initial_prompt,
which claude receives as a CLI arg and processes immediately on first spawn.

Removes prefill.py and test_prefill.py entirely; cleans up the PrefillLauncher
protocol, _launch_prefill, _wants_prefill, _config_volume_exists, and
_maybe_prefill from local_runner.py; drops memo= from the spawner→runner call;
and fixes the MCP initial_prompt description (was "prefilled unsent", now
correctly describes the immediate-processing behaviour).

Co-authored-by: Panopticon <panopticon@local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(dashboard): replace workflow text inputs with WorkflowConfigScreen modal

The repo form's enabled/disabled workflow fields were free-text comma-separated
inputs with no discovery β€” users had to know workflow names exactly. Replace them
with a dedicated WorkflowConfigScreen that lists all known workflows as a togglable
checklist, showing each workflow's name, opt-in badge, and when_to_use description
as you Tab through.

RepoFormScreen now shows a one-line summary ("N opted-in, M disabled" / "defaults")
and a "configure workflows" button that opens the modal. The opt-in/opt-out semantics
are handled internally: checked opt-in workflows land in enabled_workflows; unchecked
opt-out workflows land in disabled_workflows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(dashboard): move workflow config to a tab on the repos modal

Instead of a separate WorkflowConfigScreen sub-modal accessed via a button in
the repo edit form, workflow preferences are now a native tab on ReposScreen
itself. The repos modal shows two tabs: "repos" (the existing DataTable) and
"workflows" (a SpaceCheckbox list for the highlighted repo, with a when_to_use
description pane and Ctrl+S to save).

WorkflowConfigScreen is removed; RepoFormScreen reverts to managing only core
repo fields; ReposScreen fetches the workflow list on mount and rebuilds the
checklist on tab switch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(dashboard): move workflow config to a tab on the repo form modal

The workflow opt-in/opt-out checklist is now a second tab ("workflows") inside
RepoFormScreen, sitting alongside the existing "general" tab. Both tabs' values
are collected together on form save (Enter or Ctrl+S from any field).

ReposScreen reverts to a plain DataTable list with no workflow tab of its own β€”
workflows are configured per-repo in the create/edit form where the rest of that
repo's settings live.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(dashboard): drop [opt-in] label from workflow checkboxes

The suffix described the workflow's default behaviour (opt-in vs opt-out),
not whether it was enabled β€” which is exactly what the checkbox state conveys.
Remove it so the UI reads as an enabled/disabled toggle, not a type indicator.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(dashboard): stable modal height on tab switch; fix opt_in bool serialization

Two bugs:
- RepoFormScreen resized when switching tabs because `height: auto` tracked
  the active tab's content. Fixed by setting `height: 80%`.
- Workflow checkboxes showed all workflows as enabled because the service was
  serializing opt_in as the string "true"/"false" (always truthy in Python).
  WorkflowInfo.opt_in is now bool; service emits the raw bool.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(workflows): make local-git-self-reviewed opt-in; fix opt_in test to expect bool

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(dashboard): workflow list fills the modal height

Remove the fixed max-height cap on wf-scroll; let form-tabs, pane-workflows,
and wf-scroll each take 1fr so the scrollable list stretches to fill the
available modal space, with the description pane pinned at the bottom.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(dashboard): add enter/esc hint to repo form modal

A dim centred hint line below the tabs is visible on both the general
and workflows tabs, so the user always knows how to save or cancel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon <panopticon@local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
tildesrc and others added 13 commits July 8, 2026 20:13
…sum (#237)

* feat(container): track cost-weighted tokens instead of raw four-tier sum

tokens_used was a raw sum of all token tiers, dominated by cheap cache-reads
(~0.1Γ— price), making it ~300Γ— larger than token_estimate β€” a units mismatch,
not bad estimation. Replace with cost-weighted input-equivalent tokens
(cache-reads Γ—0.1, output Γ—5.0) via a new pricing module, so the measured
quantity is both a better billing signal and a sensible estimate target.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: flag cost-weighted prompt guidance as tech debt for non-Claude agents

TODO comments in pricing.py (canonical), planned_workflow.py, and orchestrator.py
note that the β‰ˆ0.1Γ—/β‰ˆ5Γ— framing in planning prompts is Anthropic-specific and will
need to be generalised when non-Claude LLM backends are supported.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon <panopticon@localhost>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…238)

* feat(artifacts): hide dotfile artifacts by default in the dashboard

Artifacts whose names start with '.' are now valid and hidden from the
dashboard artifact modal by default β€” a 'Show hidden' checkbox appears
when any exist. The babysit skill state files are renamed to use dot
prefixes so they don't clutter the artifact list.

- core/artifacts.py: relax validate_segment() β€” dotfile names are now
  allowed; only '.' and '..' (directory sentinels) remain forbidden.
- terminal/dashboard.py: ArtifactScreen filters dotfile names on open;
  a SpaceCheckbox('Show hidden') appears when hidden artifacts exist and
  toggles them in/out of the OptionList.
- workflows/github_forge.py: rename babysit-ci-state.json β†’
  .babysit-ci-state.json and babysit-merge-state.json β†’
  .babysit-merge-state.json in the skill instructions.
- tests: update traversal-rejection tests (remove .hidden from bad-name
  lists), add dotfile round-trip tests for the store and MCP layer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(tech-debt): flag Claude-specific token cost prompts for multi-agent generalisation

TODO markers in planned_workflow.py (TOKEN_ESTIMATED responsibility) and
orchestrator.py (spawn-task recipe step 4) noting that the 'tokens' unit
and set_token_estimate tool are Claude-specific and need revisiting when
non-Claude agents are supported.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Revert "chore(tech-debt): flag Claude-specific token cost prompts for multi-agent generalisation"

This reverts commit b0855c0.

* feat(artifacts): right-justify the Show hidden checkbox in the artifact modal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* revert: remove right-justify wrapper from Show hidden checkbox

Left-aligned is the idiomatic position for checkboxes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon Agent <agent@panopticon.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…me label to "active agents" (#240)

When Textual fires _bindings_ready (modal open/close, focus change) Footer.recompose()
recreates its children, resetting the counter Static to "". With width:auto the empty
widget collapses and the key-binding hint pills expand to cover it. Fix by storing
_counter_text on _StatusFooter and seeding the Static with it on each recompose.
Also rename the label from "agent N/M" to "active agents N/M".

Co-authored-by: Panopticon Agent <agent@panopticon.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(dashboard): open memo in \$EDITOR with ctrl+g

Pressing ctrl+g while in the MemoScreen's text input suspends the
Textual app and opens the current text in \$EDITOR (falling back to vi),
then writes the result back into the input on editor exit. Uses
shlex.split on the editor value so multi-word settings like
"code --wait" work correctly. Catches SuspendNotSupported and shows a
notification in headless/web environments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(dashboard): multi-line memo support β€” TextArea + slug truncation

Replace MemoScreen's single-line Input with a TextArea so memos edited
via ctrl+g ($EDITOR) can contain newlines. Submit moves from Enter to
ctrl+s (matching RepoFormScreen; Enter now inserts newlines). Truncate
multi-line memos to the first line in the slug cell so table row height
stays consistent; the detail pane already handles multi-line fine. Drop
"one-line" from the MCP tool docstring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(dashboard): Enter submits memo modal β€” MemoTextArea subclass

Replace the ctrl+s submit key with Enter (restoring original UX) by
subclassing TextArea as MemoTextArea and overriding _on_key to call
action_submit instead of inserting a newline on Enter. The TextArea
still displays multi-line content from ctrl+g ($EDITOR); the editor
is the intended path for multi-line memos.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(dashboard): MemoTextArea auto-expands to fit content (up to 10 rows)

Start the memo field at 1 row (single-line look); on_text_area_changed
updates styles.height to the line count capped at MAX_LINES=10, so
content loaded via ctrl+g ($EDITOR) expands the field to show all lines
without a fixed tall box in the common single-line case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(dashboard): compact=True on MemoTextArea so text is visible at height 1

Without compact mode TextArea has internal padding that pushes content
out of view when the widget is a single row tall, making typed text
invisible. compact=True removes that padding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(memo-editor): enter submits from checkbox, add ctrl+g hint label

Enter on the checkbox now submits the memo modal (via the screen-level
binding); event.stop() in MemoTextArea._on_key prevents double-fire.
A dim hint label "ctrl+g: open in $EDITOR" is shown below the checkbox.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Panopticon Agent <agent@panopticon.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Log key lifecycle events at INFO (state transitions, task creation, slug
changes, claim/release, registration, provisioning, runner events, cascade
drops) and DEBUG (url, blocked, responsibilities, artifacts, lifecycle
phases, MCP tool invocations). Mirrors the session-service logging pattern
(`_log = logging.getLogger(__name__)`, basicConfig in the entry point).

Co-authored-by: Panopticon <panopticon@example.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
After `make stop` + `make start`, tasks stayed `claimed_by="local"` in
SQLite, so the runner immediately healed them on restart. With a cached
image and existing workspace the spawn completed in 1–3 s β€” before the
dashboard's first render β€” making one task appear `live` with no visible
lifecycle phases while the others showed `healing`.

Two changes to `make stop`:

1. Reclaim tasks first (`POST /runners/local/reclaim`) so they reset to
   `queued` before the service is killed. After `make start` the dashboard
   shows `queued`, then the runner claims and spawns through the full
   visible lifecycle. Best-effort: the curl fails silently if the service
   is already down.

2. Switch the docker container filter from `name=^panopticon-` (regex
   anchor semantics vary by Docker version) to `label=panopticon.task`
   (containers are already labeled in `LocalRunner.spawn`), which is
   reliable and version-independent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After any restart (clean `make stop` or unexpected reboot), tasks kept
`claimed_by` in SQLite. The runner reconnected with the same ID, `heal()`
fired immediately, and with a cached image + existing workspace the spawn
completed in 1–3 s β€” before the dashboard's first render β€” so one task
always appeared `live` with no visible lifecycle phases.

`Spawner.startup_reclaim(tasks)` runs once on the first successful task
fetch (via a `startup` flag in `HostDaemon.run`). For each task claimed
by this runner it checks `is_running()`:

- Container gone (reboot / clean stop): release the claim β†’ `queued` β†’
  `spawn_one` picks it up through the full visible spawn lifecycle.
- Container still running (runner-only crash): keep the claim β†’ `heal`
  handles it normally.

Best-effort per task: a failed release is silently skipped.

Also switches `make stop`'s docker filter from `name=^panopticon-`
(regex anchor semantics vary by Docker version) to `label=panopticon.task`
(containers are already labeled in `LocalRunner.spawn`).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removed a reference to the design documentation branch.
Removed reference to CLAUDE.md from the README.
Removed status and development sections from README.
…241)

Adds a paragraph to Workflow.overview() β€” the static system prompt
injected into every container β€” telling the agent to use put_artifact
for reports and other non-code deliverables instead of printing inline
or writing ephemeral container files.

Updates the golden briefing fixture to match.

Co-authored-by: Panopticon <panopticon@local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants