Skip to content

Add compose-based preview stack for the reasoning dashboard - #39

Open
pankaj4u4m wants to merge 643 commits into
mainfrom
shipit/xjaudd
Open

Add compose-based preview stack for the reasoning dashboard#39
pankaj4u4m wants to merge 643 commits into
mainfrom
shipit/xjaudd

Conversation

@pankaj4u4m

Copy link
Copy Markdown
Collaborator

Summary

The preview panel had nothing to work with: this repo had no shipit.yaml and no compose file at all, so ShipIt fell through to its onboarding UI. Adding a compose: key alone was not possible — there was no compose file to point at — so this change creates both, wired to the one genuinely previewable surface in the repo: the Vite + React reasoning dashboard.

Rationale

Preview = the frontend dashboard, on 3125. It mirrors the native make start stack (lemoncrow stack start), keeping the ports the project already uses (frontend 3125, api 8787) rather than the generic Vite/FastAPI defaults, so the preview matches local dev and VITE_API_URL conventions.

The api service is manual, not auto. lemoncrow.core.service.api imports lemoncrow.pro, a private subpackage referenced 327 times across src/ that is absent from this checkout and is not a submodule. The service therefore cannot boot from the open-source repo — verified: it exits 1 on ModuleNotFoundError: No module named 'lemoncrow.pro'. Marking it auto would put a crash-looping container behind the preview pane. As manual it stays a one-command opt-in (shipit service start api) that works as-is in a checkout that has src/lemoncrow/pro. depends_on: api is deliberately omitted so the preview doesn't drag the manual service up with it.

Python deps install in the service, not agent.install. A virtualenv is pinned to the interpreter that created it, and the python:3.13 service's interpreter is not the agent container's. Both venvs are placed outside the mounted workspace (/tmp/uvenv, /tmp/venv) specifically so the service can never clobber the agent's own ./.venv, which uv run depends on per CLAUDE.md. uv sync --frozen honours uv.lock and never rewrites it, keeping the working tree clean.

uv sync --no-install-project + PYTHONPATH=/app/src rather than an editable install. This is forced by a pre-existing repo bug (below), but it is also the better preview shape: source edits are live with no reinstall step.

Two pre-existing repo bugs found while verifying (not fixed here)

Both are independent of this change and affect anyone building or running the project:

  1. pyproject.toml force-includes a file that does not exist. [tool.hatch.build.targets.wheel.force-include] names src/lemoncrow/pro/capabilities/code_context/explore_reranker_model.json, which has never been committed (absent from HEAD). Every wheel and editable build fails with FileNotFoundError: Forced include not found. This breaks uv run in the agent container too, so CLAUDE.md's documented uv run pytest / uv run mypy workflow does not currently work from a clean checkout.
  2. lemoncrow.pro is missing but hard-imported. src/lemoncrow/core/capabilities/host_router_bridge.py:10 imports it unguarded, making the FastAPI service unimportable in this repo.

Changes

  • shipit.yaml (new) — declares compose: docker-compose.yml, which is what enables the preview panel. agent.install runs npm ci --prefix frontend because frontend/node_modules is absent from a fresh checkout and the dev server needs it. Explicit install-inputs re-enables the content-keyed install skip (the --prefix form isn't auto-recognised), and dep-dirs points the overlay store at frontend/node_modules.
  • docker-compose.yml (new)frontend (node:20-slim, auto, gated on install) and api (python:3.13, manual, self-installing venv), with LEMONCROW_REQUIRE_AUTH: "0" so the non-loopback bind doesn't 503 every protected route in the sandbox, and LEMONCROW_ROOT/HOME pointed at /tmp to keep the SQLite store and caches out of the git tree.
  • frontend/vite.config.ts — added server.watch polling, opt-in via VITE_USE_POLLING (set only in compose). Required because inotify events don't cross the agent/service mount-namespace boundary, so hot reload would silently no-op on agent edits; gating it keeps the cheaper default watcher for native npm run dev.

Test plan

Verified in this session:

  • shipit service list reconciles to frontend running auto 3125 / api stopped manual 8787.
  • Dashboard loads in the browser at :3125 — nav, stat tiles, and window selector render, degrading gracefully to "Daemon unreachable" with the api service stopped (expected without lemoncrow.pro).
  • Hot reload confirmed end-to-end: editing frontend/src/pages/Overview.tsx from the agent container produced [vite] hmr update /src/pages/Overview.tsx in the service log. The probe edit was reverted (git diff clean).
  • npm --prefix frontend run typecheck passes with the vite.config.ts change.
  • api failure mode confirmed by reading its logs, not assumed.

To check the full stack in a checkout that has src/lemoncrow/pro: shipit service start api, then confirm the "Daemon unreachable" chip turns healthy and the stat tiles populate.

pankaj4u4m and others added 30 commits July 15, 2026 11:15
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
verify_before_done, pre_tool_discipline, and live_review early-exit (no
steering/output) when the cap is exhausted, so a dormant free session runs as if
LemonCrow weren't installed. Fail-open. Measurement/reporting/session-lifecycle
hooks are NOT gated so usage is still metered and a free user recovers.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
… token

Fresh machines (new install/dev/CI) that never received a server token use the
local meter (active) instead of failing closed; the token-persist path drops a
.cap_established marker, after which the compiled gate token-gates the free tier.
Mirrors the Pro established grace. Fixes the 17 no-token-dormant regressions.
(--no-verify: staged hunk is mypy+test+ruff clean; pre-commit tripped on an
unrelated concurrent working-tree edit.)

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
…derivation

The anon usage report now includes sha256(device_id) so the server derives a
stable, unforgeable anon-id (deleting the local anon token can't reset savings).
Only the hash is sent, never the raw machine id.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
A never-established machine uses the editable local meter only while genuinely
fresh; once its oldest session savings file is older than 48h it enters
fail-closed enforcement (it has had time to check in). Ties the grace to the
same session files the meter is computed from, so resetting it means deleting
ALL session history. CI/test/new-install (no old sessions) stay active with no
server. Compiled in — no flag disables it.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Deleting LemonCrow's own sessions/*/savings.jsonl no longer resets the
free-tier grace window: _free_grace_over now also consults the user's
real host CLI history (~/.claude, ~/.codex, opencode DB) via the existing
session_parsers, so a long-lived machine can't be made to look freshly
installed without erasing its actual conversation history.

- session_recall.host_session_activity_before(cutoff): early-exit scan of
  Claude/Codex/OpenCode session files, host roots via CLAUDE_CONFIG_DIR/
  CODEX_HOME/XDG_DATA_HOME (test-isolable).
- conftest isolates CODEX_HOME + XDG_DATA_HOME so CI stays hermetic.
- tests: grace-over from Claude transcript + Codex session; recent host
  history stays within grace (local meter).

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
MCP host configs (Claude Code, opencode) spawn the bare `lc` command;
~/.local/bin is on PATH far more reliably than LEMONCROW_BIN_DIR across
non-login/GUI-spawned shells. Also fixes a mismatched-quote bug in
ensure_lc_alias's basename resolution.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Drop the verbose additionalContext blocks; the one-line message is enough
and keeps the codex hook payload small.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Slotted-object reconstruction (copy.copy/__setstate__) does setattr(y,
'_conn', conn) on a fresh instance before the slot exists; forwarding that
to the not-yet-set wrapped connection raised AttributeError. Special-case
the slot itself.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
… in replay examples

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
…ree install

The v0.4.4 host-anchor made _free_grace_over consult real ~/.claude/
~/.codex/opencode history. But essentially every free user has >48h-old
host CLI transcripts, so a FRESH LemonCrow install (no sessions/ ledger,
never checked in) tripped grace-over immediately -> fail-closed -> zero lc
tools, before it could ever obtain a token. The anchor also can't
distinguish a genuinely-new lc user from a tamperer (both look like 'old
host history + no lc sessions'), so the false-positive is unavoidable.

Grace is now keyed back to LemonCrow's OWN per-session ledger age (how long
THIS install has run). The real anti-tamper stays intact: .cap_established
fail-closes any machine that has ever received a token, and the server
re-derives cap state from accumulated account savings on re-check-in.

Adds regression tests: old host history must NOT brick a fresh free install.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Thread a steal flag through init -> _index_repo_with_progress ->
index_repo: when the write lock can't be acquired within the timeout,
break the stale lock file (orphaning the old holder's flock) and re-open
fresh, so a wedged/crashed indexer can't block a must-succeed rebuild.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
When the savings cap is reached the lc MCP tools are hidden, but the
per-workspace AGENTS.md guide still told the agent to 'route everything
through LemonCrow tools' — and its fallback even told it to HUNT for the
missing tools. Rewrite the fallback: if the tools are still absent after a
tool_search, LemonCrow is dormant for this session, so ignore the guide and
use native tools as if LemonCrow were not installed.

Static one-time content (written into AGENTS.md at install) — the model
self-gates on tool presence. No runtime strip/restore of the user's own
AGENTS.md (no per-session churn); no fragile file stashing.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
…+ agents

Global installs write wholly-LemonCrow-owned files under the host config home
($CODEX_HOME / $OPENCODE_CONFIG_HOME), so unlike a project's own AGENTS.md
(soft-gated) they're safe to edit/move directly when dormant. reset_lemoncrow_
global_dormancy(host, dormant) is idempotent and self-healing per surface:

- codex: strip/re-upsert the <!-- LEMONCROW --> AGENTS.md block (regenerated
  from source, not stashed -> no state to lose; writes only on real change),
  atomic-rename the plugin skills dir aside, stash lemoncrow.* agent files.
- opencode: stash lemoncrow.* global agent files (no global AGENTS.md/skills).

Every step no-ops when its target is absent, so workspace-only installs and a
user's own (non-lemoncrow.*) agents are never touched. Wired into the same
SessionStart/prompt seams as the existing workspace agent reset. Extracts the
shared stash core into _stash_agent_files.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
The report already carried the subscription meter (compute_usage_meter) in its
payload -- so 'lc savings --json' already had every cap field -- but the human
view only printed a bare Plan line. Render a Cap line beneath it:

  Cap   $14.20 of $20.00 (30d)  · 71.0% used, $5.80 left   [local est.]
  Cap   $22.90 of $20.00 (30d)  — CAP REACHED · LemonCrow dormant   [server]
  Cap   uncapped   [server]  (pro/enterprise)

Keyed to the monthly cap window (windowDays), NOT the ad-hoc 1/7/30d windows
above, and sourced from the server meter when present (else a local estimate),
so it can never disagree with the actual dormancy decision. free $20 / lite
$200 / pro uncapped all render from their own cap value.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Green when within the cap, red (with CAP REACHED · dormant) when over. The
red/green boundary is keyed on savingsOverCap -- the SAME >= flag that drives
dormancy -- so the colour flips at exactly the point the machine goes dormant,
covering the savings==cap boundary correctly (renders red). Reuses the existing
statusline ANSI palette; click.echo strips ANSI on non-TTY and NO_COLOR /
LEMONCROW_NO_COLOR force it off; the [source] tag stays uncoloured.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
…e 1)

Closes the design gap where is_pro() trusted the UNSIGNED plan from
/api/auth/me — forgeable from local disk (edit auth.json, or point
'account login --dev' at a self-run localhost:4321 returning {plan:pro}),
which bypassed the cap entirely since 'if has_pro: return False'.

- licensing_gate.plan_from_token(): Ed25519-verify a signed plan token with
  the SAME pinned key as the cap verdict; returns the signed plan or None.
- entitlements._entitled_plan(): prefer the signed plan; a present-but-invalid
  token drops to free (never trust unsigned alongside a bad token).

Phased rollout: _REQUIRE_SIGNED_PLAN=False (default) still honours an unsigned
plan when no token is present, so pro sessions predating token issuance keep
working. Flip to True once the auth server issues plan_token for every session
— then only a valid signed token grants pro. Server side (issue plan_token in
/api/auth/me) is the remaining step before the flip.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
pankaj4u4m and others added 28 commits August 2, 2026 22:49
Group the 14 flat top-level docs files under docs/ into structured
folders by topic: setup/, reference/, legal/, planning/, operations/.
Add _category_.json for each new folder, rewrite the docs/README.md
index, and update sidebars.ts to match the new hierarchy.

Fix navigation links broken by the move:
- docusaurus.config.ts footer routes (/installation, /cli,
  /troubleshooting, /privacy -> /setup|reference/...)
- docs-site/index.tsx and landing cross-links to moved docs pages

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
…s note

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Durable retry state (15m->6h backoff), per-tick due check, POST retries, and per-day occurred_at/real totals/carry_tokens; drop duplicate codex stop-hook publish. Bumps landing to the matching worker fix.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Free Zen models (Bearer 'public') route through litellm as zen/<model>.
Only competes when no other vendor is configured. Also gates ollama on a
reachability probe so an installed-but-dead daemon no longer wins routing.
Writes a JSON snapshot (model, tokens, cache, spend, tool calls, local
index) that the lemoncode TUI sidebar polls. Also fixes three lc code
bugs: loopback health probe now bypasses HTTP(S)_PROXY, model label no
longer renders 'LemonCode LemonCode', and the output governor grants
reasoning-aware headroom instead of hard-truncating reasoning models.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Adds --driver lemoncode with per-arm containers on Zen big-pickle, and
teaches the flow parser OpenAI-shaped usage (JSON + SSE) so non-Anthropic
arms are counted at all. swe-lite 10x2: 9.22M -> 5.11M tokens (-44.6%),
301 -> 191 requests, 0/10 correct on both arms.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
LemonCode is LemonCrow's own opencode fork, so it moves from a coding
engine to a full host: session importer, detection, dormancy, workspace
overrides, routing contract, swarm runner, install/uninstall/verify
scripts, integrations/lemoncode, docs and UI. Shares opencode's on-disk
shapes (.opencode/, opencode.db) with its own XDG app dir
~/.config/lemoncode.
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
…OGO=1)

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Selecting LemonCode now installs it. Previously both paths required a
separate 'lc code host install': --engine lemoncode raised, and the
installer printed SKIPPED and exited 0.

Detection was also probing 'command -v lemoncode', which is the lemoncrow
wheel console script (an alias for 'lc code'), not the host binary at
<store>/bin/lemoncode-host.
README, CONTRIBUTING, and docs-internal referenced pre-reorg flat
docs/ paths (docs/architecture.md, docs/installation.md, etc.) that
now live under docs/{reference,setup,operations,planning,hosts}/.
Repo-wide link scan now reports 0 broken (excl. gitignored
docs-site/docs build output and vendored fixtures).

CONTRIBUTING.md also linked docs/architecture/POSITIONING_AND_ADOPTION.md,
which never existed in history; de-linked rather than invent a target.
- add telemetry_cadence.py as single source for push interval, used by
  usage_report.py and public_rollup.py to stop drift
- fix dual-daemon registration race (403 outage): heartbeat/liveness and
  teardown now respect socket ownership (stack_lifecycle, servicectl_lifecycle)
- update pricing.yaml/pricing.py, savings_summary, automation
- regenerate SKILL/agent docs via sync-agent-context; refresh marketing docs,
  roadmap, README, BENCHMARKS, CLI/architecture/mcp reference
- add regression test for daemon ownership races; extend knowledge_store,
  test_paths

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
…acking

- Updated benchmark documentation to reflect changes in terminology from "modes" to "channels" and clarified the purpose of each.
- Introduced a new `--mode` option for `lc benchmark codebench` to allow for cost, budget, and ceiling comparisons.
- Implemented logic in the benchmark gate to evaluate completion rates for ceiling tasks instead of cost.
- Added context tracking for live statusline updates, including context percentage and token usage.
- Enhanced savings summary to include runway estimates based on context usage.
- Developed tests for new benchmarking modes and context tracking features to ensure functionality and reliability.
Matches Claude Code/Codex CLI/OpenCode: only pre-select hosts the
install wizard actually finds. LemonCode stays always-selected since
choosing it installs the binary; Cursor doesn't self-install.
… and ports in `service list`), which is the real va
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant