Add compose-based preview stack for the reasoning dashboard - #39
Open
pankaj4u4m wants to merge 643 commits into
Open
Add compose-based preview stack for the reasoning dashboard#39pankaj4u4m wants to merge 643 commits into
pankaj4u4m wants to merge 643 commits into
Conversation
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>
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The preview panel had nothing to work with: this repo had no
shipit.yamland no compose file at all, so ShipIt fell through to its onboarding UI. Adding acompose: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 startstack (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 andVITE_API_URLconventions.The
apiservice ismanual, notauto.lemoncrow.core.service.apiimportslemoncrow.pro, a private subpackage referenced 327 times acrosssrc/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 onModuleNotFoundError: No module named 'lemoncrow.pro'. Marking itautowould put a crash-looping container behind the preview pane. Asmanualit stays a one-command opt-in (shipit service start api) that works as-is in a checkout that hassrc/lemoncrow/pro.depends_on: apiis 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 thepython:3.13service'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, whichuv rundepends on per CLAUDE.md.uv sync --frozenhonoursuv.lockand never rewrites it, keeping the working tree clean.uv sync --no-install-project+PYTHONPATH=/app/srcrather 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:
pyproject.tomlforce-includes a file that does not exist.[tool.hatch.build.targets.wheel.force-include]namessrc/lemoncrow/pro/capabilities/code_context/explore_reranker_model.json, which has never been committed (absent fromHEAD). Every wheel and editable build fails withFileNotFoundError: Forced include not found. This breaksuv runin the agent container too, so CLAUDE.md's documenteduv run pytest/uv run mypyworkflow does not currently work from a clean checkout.lemoncrow.prois missing but hard-imported.src/lemoncrow/core/capabilities/host_router_bridge.py:10imports it unguarded, making the FastAPI service unimportable in this repo.Changes
shipit.yaml(new) — declarescompose: docker-compose.yml, which is what enables the preview panel.agent.installrunsnpm ci --prefix frontendbecausefrontend/node_modulesis absent from a fresh checkout and the dev server needs it. Explicitinstall-inputsre-enables the content-keyed install skip (the--prefixform isn't auto-recognised), anddep-dirspoints the overlay store atfrontend/node_modules.docker-compose.yml(new) —frontend(node:20-slim,auto, gated on install) andapi(python:3.13,manual, self-installing venv), withLEMONCROW_REQUIRE_AUTH: "0"so the non-loopback bind doesn't 503 every protected route in the sandbox, andLEMONCROW_ROOT/HOMEpointed at/tmpto keep the SQLite store and caches out of the git tree.frontend/vite.config.ts— addedserver.watchpolling, opt-in viaVITE_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 nativenpm run dev.Test plan
Verified in this session:
shipit service listreconciles tofrontend running auto 3125/api stopped manual 8787.:3125— nav, stat tiles, and window selector render, degrading gracefully to "Daemon unreachable" with the api service stopped (expected withoutlemoncrow.pro).frontend/src/pages/Overview.tsxfrom the agent container produced[vite] hmr update /src/pages/Overview.tsxin the service log. The probe edit was reverted (git diffclean).npm --prefix frontend run typecheckpasses with thevite.config.tschange.apifailure 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.