lemming-cli 0.4.6__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/PKG-INFO +53 -25
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/README.md +51 -24
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/SKILL.md +72 -5
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/pyproject.toml +2 -1
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/exec_cli.py +22 -5
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/exec_cli_test.py +248 -1
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/main_test.py +1 -1
- lemming_cli-0.5.0/src/lemming/cli/skill.py +7 -0
- lemming_cli-0.5.0/src/lemming/cli/skill_test.py +47 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/orchestrator.py +101 -46
- lemming_cli-0.5.0/src/lemming/prompts/hooks/60-testing.md +65 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/prompts/hooks/90-roadmap.md +4 -3
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/uv.lock +19 -1
- lemming_cli-0.4.6/src/lemming/cli/skill.py +0 -344
- lemming_cli-0.4.6/src/lemming/cli/skill_test.py +0 -151
- lemming_cli-0.4.6/src/lemming/prompts/hooks/60-testing.md +0 -48
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/.dockerignore +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/.github/workflows/ci.yml +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/.github/workflows/publish.yml +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/.github/workflows/screenshots.yml +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/.gitignore +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/.prettierignore +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/.prettierrc +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/Dockerfile +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/LICENSE +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/biome.json +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/docker-compose.yml +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/docs/EVALS.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/docs/HOOKS.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/docs/screenshots/dashboard-desktop.png +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/docs/screenshots/dashboard-mobile.png +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/docs/screenshots/task-log-desktop.png +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/docs/screenshots/task-log-mobile.png +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/package-lock.json +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/package.json +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/playwright.config.js +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/pyrefly.toml +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/auth.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/auth_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/config.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/config_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/conftest.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/context.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/context_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/directories.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/directories_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/files.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/files_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/hooks.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/hooks_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/logging.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/logging_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/loop.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/loop_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/main.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/main_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/tasks.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api/tasks_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/api_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/brief_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/brief.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/config.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/config_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/goal.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/goal_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/hooks.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/hooks_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/machine_output_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/main.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/operations.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/operations_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/progress.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/progress_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/readability_cli.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/readability_cli_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/stop_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/tasks.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli/tasks_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/cli_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/conftest.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/__main__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/cli.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/cli_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/container.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/container_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/fixtures.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/fixtures_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/harness.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/harness_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/metrics.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/metrics_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/base/README.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/base/calc/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/base/calc/legacy.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/base/calc/ops.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/base/calc/ops_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/clean/calc/ops.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/clean/calc/ops_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/dead-code/calc/ops.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/dead-code/calc/ops_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/duplicated-behavior/calc/ops.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/duplicated-behavior/calc/ops_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/false-reuse/calc/limits.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/false-reuse/calc/limits_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/lint-debt/calc/ops.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/readability/lint-debt/calc/ops_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/add-only/README.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/add-only/calc/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/add-only/calc/ops.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/add-only/calc/ops_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/buggy-subtract/README.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/buggy-subtract/calc/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/buggy-subtract/calc/ops.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/buggy-subtract/calc/ops_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/full-ops/README.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/full-ops/calc/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/full-ops/calc/ops.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/full-ops/calc/ops_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/unwired-cli/README.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/unwired-cli/calc/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/unwired-cli/calc/cli.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/unwired-cli/calc/cli_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/unwired-cli/calc/ops.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/roadmap/unwired-cli/calc/ops_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/task/hidden/stats/summary_hidden_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/task/summary/README.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/task/summary/stats/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/task/summary/stats/summary.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/projects/task/summary/stats/summary_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/readability.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/readability_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/report.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/report_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/roadmap.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/roadmap_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/scenarios.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/scenarios_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/suites.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/task.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/task_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/trial.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/evals/trial_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/hooks.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/hooks_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/integration_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/main.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/main_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/models.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/models_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/orchestrator_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/paths.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/paths_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/persistence.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/persistence_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/prompts/hooks/50-readability.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/prompts/hooks/70-ux.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/prompts/taskrunner.md +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/prompts.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/prompts_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/providers.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/providers_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/runner.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/runner_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/scope.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/scope_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/shutdown.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/shutdown_integration_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/shutdown_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/__init__.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/lifecycle.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/lifecycle_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/limits.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/operations.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/operations_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/progress.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/progress_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/queries.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/tasks/queries_test.py +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/dashboard.spec.js +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/dashboard.test.js +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/favicon.js +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/favicon.spec.js +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/files.html +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/files.spec.js +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/index.html +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/index.js +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/logs.html +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/logs.test.js +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/mancha.js +0 -0
- {lemming_cli-0.4.6 → lemming_cli-0.5.0}/src/lemming/web/screenshots.spec.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: lemming-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: An autonomous, iterative task runner for AI coding agents.
|
|
5
5
|
Project-URL: Homepage, https://github.com/owahltinez/lemming
|
|
6
6
|
Project-URL: Repository, https://github.com/owahltinez/lemming
|
|
@@ -10,6 +10,7 @@ License-File: LICENSE
|
|
|
10
10
|
Keywords: agents,ai,antigravity,automation,claude,opencode
|
|
11
11
|
Requires-Python: >=3.12
|
|
12
12
|
Requires-Dist: beautifulsoup4>=4.13.3
|
|
13
|
+
Requires-Dist: click-agentcli>=0.3.0
|
|
13
14
|
Requires-Dist: click>=8.0.0
|
|
14
15
|
Requires-Dist: fastapi>=0.124.4
|
|
15
16
|
Requires-Dist: markdownify>=0.14.1
|
|
@@ -112,10 +113,19 @@ runner, and the agent's closing message comes back on stdout.
|
|
|
112
113
|
# Delegate one task to a different agent, e.g. to spare another's quota
|
|
113
114
|
lemming exec "Fix the flaky test in runner_test.py" --runner codex
|
|
114
115
|
|
|
116
|
+
# Allow up to three total attempts for transient runner failures
|
|
117
|
+
lemming exec "Fix the flaky test in runner_test.py" --retries 3
|
|
118
|
+
|
|
115
119
|
# Pipe a longer handoff instead of fighting shell quoting
|
|
116
|
-
cat handoff.md | lemming exec -f - --runner agy
|
|
120
|
+
cat handoff.md | lemming -v exec -f - --runner agy
|
|
117
121
|
```
|
|
118
122
|
|
|
123
|
+
The runner receives no conversation history and cannot be steered mid-run.
|
|
124
|
+
Make the handoff self-contained: state the goal, hard constraints, relevant
|
|
125
|
+
findings and evidence, approaches ruled out and why, and the definition of done
|
|
126
|
+
and verification. The installed skill includes a complete here-document
|
|
127
|
+
example for orchestrating agents.
|
|
128
|
+
|
|
119
129
|
With no description there is nothing for a task runner to do, so only the
|
|
120
130
|
reviews run — against work that already exists.
|
|
121
131
|
|
|
@@ -124,7 +134,7 @@ reviews run — against work that already exists.
|
|
|
124
134
|
lemming exec --review readability
|
|
125
135
|
|
|
126
136
|
# Review someone else's branch, checked out in a worktree
|
|
127
|
-
lemming
|
|
137
|
+
lemming -C ../review-worktree exec --review testing --scope main...HEAD
|
|
128
138
|
|
|
129
139
|
# Do the work, then gate it
|
|
130
140
|
lemming exec "Add pagination to the tasks API" --review all
|
|
@@ -135,13 +145,14 @@ which is resolved to the files it changed. It defaults to uncommitted work, or
|
|
|
135
145
|
to the whole tree outside a git repository.
|
|
136
146
|
|
|
137
147
|
Each run is self-contained: nothing is read from the project's roadmap or its
|
|
138
|
-
local hooks,
|
|
139
|
-
removed unless it failed — in which case it is kept, and its path
|
|
140
|
-
the log can be read. Kept directories live in
|
|
141
|
-
retired automatically a week later, so a
|
|
142
|
-
inspect. Stdout carries the agent's
|
|
143
|
-
stderr, so the output can be consumed
|
|
144
|
-
tasks file and task ID at startup; pass
|
|
148
|
+
local hooks, it runs only the requested task and reviews, and its state
|
|
149
|
+
directory is removed unless it failed — in which case it is kept, and its path
|
|
150
|
+
printed, so the log can be read. Kept directories live in
|
|
151
|
+
`~/.local/lemming/exec-*` and are retired automatically a week later, so a
|
|
152
|
+
recent failure is always still there to inspect. Stdout carries the agent's
|
|
153
|
+
message alone and everything else goes to stderr, so the output can be consumed
|
|
154
|
+
directly. Stderr reports the ephemeral tasks file and task ID at startup; pass
|
|
155
|
+
those to
|
|
145
156
|
`lemming --tasks-file <path> status <id>` or `logs <id>` to inspect an active
|
|
146
157
|
run. Use the global verbose flag (`lemming -v exec ...`) to stream runner
|
|
147
158
|
activity.
|
|
@@ -149,25 +160,40 @@ activity.
|
|
|
149
160
|
Note that the agent runs unattended (`--yolo` by default), so it does not
|
|
150
161
|
inherit the permission prompts of whatever launched it.
|
|
151
162
|
|
|
163
|
+
`--retries N` includes the first attempt and defaults to 1. Retries reuse the
|
|
164
|
+
same task state and progress after incomplete runs, timeouts, launch errors, or
|
|
165
|
+
non-zero exits. An explicit failure or cancellation, an interruption, or a
|
|
166
|
+
failed review stops immediately. Review-only runs cannot be retried.
|
|
167
|
+
|
|
168
|
+
Concurrent writing runs must not share a checkout. Lemming stays independent of
|
|
169
|
+
Git, Mercurial, and other version control systems: the caller creates a separate
|
|
170
|
+
working copy with the repository's existing VCS, passes it with
|
|
171
|
+
`lemming -C <working-copy> -v exec ...`, and owns result recovery and cleanup.
|
|
172
|
+
For Git, stop when the source checkout has modified or untracked files instead
|
|
173
|
+
of silently excluding them. Retain every isolated working copy until its changes
|
|
174
|
+
have been recovered. The packaged skill includes a minimal Git example.
|
|
175
|
+
|
|
152
176
|
### Teaching Your Agent to Use It
|
|
153
177
|
|
|
154
178
|
Lemming ships an Agent Skill so that an agent already running — Codex, Claude
|
|
155
179
|
Code, Gemini CLI, Cursor — can reach any other agent CLI without knowing how
|
|
156
|
-
each one spells its flags. Install it
|
|
180
|
+
each one spells its flags. Install or refresh it with:
|
|
157
181
|
|
|
158
182
|
```bash
|
|
159
|
-
# Cross-tool location
|
|
183
|
+
# Cross-tool location plus every detected tool-specific location
|
|
160
184
|
lemming skill install
|
|
161
185
|
|
|
162
|
-
# Cover detected tools that require their own skill directory too
|
|
163
|
-
lemming skill install --all
|
|
164
|
-
|
|
165
186
|
# This repository only
|
|
166
187
|
lemming skill install --to .agents/skills
|
|
188
|
+
|
|
189
|
+
# Inspect every supported location
|
|
190
|
+
lemming skill status
|
|
167
191
|
```
|
|
168
192
|
|
|
169
|
-
`lemming skill uninstall` reverses
|
|
170
|
-
does not hold this skill, so a mistyped `--to` fails
|
|
193
|
+
`lemming skill uninstall` reverses the default installation sweep. Both refuse
|
|
194
|
+
to touch a directory that does not hold this skill, so a mistyped `--to` fails
|
|
195
|
+
instead of deleting work. Use `--link` on a durable installation to track
|
|
196
|
+
package upgrades without reinstalling.
|
|
171
197
|
|
|
172
198
|
---
|
|
173
199
|
|
|
@@ -209,9 +235,9 @@ loops through each pending task:
|
|
|
209
235
|
`lemming complete` or `lemming fail`. Agents can also schedule new tasks
|
|
210
236
|
with `lemming add`, breaking down complex work into smaller steps that
|
|
211
237
|
Lemming will pick up automatically.
|
|
212
|
-
4. **Retry or advance**: On failure, Lemming retries the task
|
|
213
|
-
|
|
214
|
-
previous attempts. On success, it moves to the next task.
|
|
238
|
+
4. **Retry or advance**: On failure, Lemming retries the task up to the
|
|
239
|
+
configured roadmap limit, with accumulated progress as context so the agent
|
|
240
|
+
learns from previous attempts. On success, it moves to the next task.
|
|
215
241
|
5. **Orchestration**: After each task, Lemming can run one or more
|
|
216
242
|
**Orchestrator Hooks** (like the built-in `roadmap` hook) to evaluate the
|
|
217
243
|
results and adapt the roadmap if needed. Hooks are enabled by default but
|
|
@@ -411,19 +437,21 @@ These come before the subcommand and apply to all of them.
|
|
|
411
437
|
revision range is resolved to the files it changed. Defaults to uncommitted
|
|
412
438
|
work, or the whole tree outside a repository.
|
|
413
439
|
- `--runner`, `--model`: Which agent CLI and model to use.
|
|
440
|
+
- `--retries`: Maximum total task-runner attempts, including the first
|
|
441
|
+
(default 1). Does not retry review-only runs.
|
|
414
442
|
- `--time-limit`: Minutes before the agent is killed (default 60, 0 for no
|
|
415
443
|
limit).
|
|
416
444
|
- `--yolo/--no-yolo`: Run the agent unattended (default: True).
|
|
417
445
|
- `--keep`: Keep the run's state directory even when it succeeds.
|
|
418
446
|
- **`skill install`**: Install the packaged Agent Skill so agents discover
|
|
419
|
-
Lemming. Writes to `~/.agents/skills`
|
|
420
|
-
|
|
447
|
+
Lemming. Writes to `~/.agents/skills` and every detected tool-specific
|
|
448
|
+
directory by default. Re-running it refreshes existing Lemming copies.
|
|
421
449
|
- `--to <dir>`: Install into a specific skills directory.
|
|
422
|
-
- `--all`: Also cover every detected tool's own skills directory.
|
|
423
450
|
- `--link`: Symlink instead of copying, so upgrades take effect immediately.
|
|
424
|
-
- `--force`: Replace an existing installation of this skill.
|
|
425
451
|
- `--dry-run`: Print what would happen, refusals included.
|
|
426
|
-
- **`skill uninstall`**: Remove it again.
|
|
452
|
+
- **`skill uninstall`**: Remove it again. Supports `--to` and `--dry-run`.
|
|
453
|
+
- **`skill status`**: Show every supported location and installation state.
|
|
454
|
+
Supports `--json` for structured output.
|
|
427
455
|
- **`stop`**: Stop the running loop and its runner.
|
|
428
456
|
- `--after-current-task`: Drain instead — let the running task finish, then
|
|
429
457
|
stop before claiming another. This is the safe way to change the runner or
|
|
@@ -90,10 +90,19 @@ runner, and the agent's closing message comes back on stdout.
|
|
|
90
90
|
# Delegate one task to a different agent, e.g. to spare another's quota
|
|
91
91
|
lemming exec "Fix the flaky test in runner_test.py" --runner codex
|
|
92
92
|
|
|
93
|
+
# Allow up to three total attempts for transient runner failures
|
|
94
|
+
lemming exec "Fix the flaky test in runner_test.py" --retries 3
|
|
95
|
+
|
|
93
96
|
# Pipe a longer handoff instead of fighting shell quoting
|
|
94
|
-
cat handoff.md | lemming exec -f - --runner agy
|
|
97
|
+
cat handoff.md | lemming -v exec -f - --runner agy
|
|
95
98
|
```
|
|
96
99
|
|
|
100
|
+
The runner receives no conversation history and cannot be steered mid-run.
|
|
101
|
+
Make the handoff self-contained: state the goal, hard constraints, relevant
|
|
102
|
+
findings and evidence, approaches ruled out and why, and the definition of done
|
|
103
|
+
and verification. The installed skill includes a complete here-document
|
|
104
|
+
example for orchestrating agents.
|
|
105
|
+
|
|
97
106
|
With no description there is nothing for a task runner to do, so only the
|
|
98
107
|
reviews run — against work that already exists.
|
|
99
108
|
|
|
@@ -102,7 +111,7 @@ reviews run — against work that already exists.
|
|
|
102
111
|
lemming exec --review readability
|
|
103
112
|
|
|
104
113
|
# Review someone else's branch, checked out in a worktree
|
|
105
|
-
lemming
|
|
114
|
+
lemming -C ../review-worktree exec --review testing --scope main...HEAD
|
|
106
115
|
|
|
107
116
|
# Do the work, then gate it
|
|
108
117
|
lemming exec "Add pagination to the tasks API" --review all
|
|
@@ -113,13 +122,14 @@ which is resolved to the files it changed. It defaults to uncommitted work, or
|
|
|
113
122
|
to the whole tree outside a git repository.
|
|
114
123
|
|
|
115
124
|
Each run is self-contained: nothing is read from the project's roadmap or its
|
|
116
|
-
local hooks,
|
|
117
|
-
removed unless it failed — in which case it is kept, and its path
|
|
118
|
-
the log can be read. Kept directories live in
|
|
119
|
-
retired automatically a week later, so a
|
|
120
|
-
inspect. Stdout carries the agent's
|
|
121
|
-
stderr, so the output can be consumed
|
|
122
|
-
tasks file and task ID at startup; pass
|
|
125
|
+
local hooks, it runs only the requested task and reviews, and its state
|
|
126
|
+
directory is removed unless it failed — in which case it is kept, and its path
|
|
127
|
+
printed, so the log can be read. Kept directories live in
|
|
128
|
+
`~/.local/lemming/exec-*` and are retired automatically a week later, so a
|
|
129
|
+
recent failure is always still there to inspect. Stdout carries the agent's
|
|
130
|
+
message alone and everything else goes to stderr, so the output can be consumed
|
|
131
|
+
directly. Stderr reports the ephemeral tasks file and task ID at startup; pass
|
|
132
|
+
those to
|
|
123
133
|
`lemming --tasks-file <path> status <id>` or `logs <id>` to inspect an active
|
|
124
134
|
run. Use the global verbose flag (`lemming -v exec ...`) to stream runner
|
|
125
135
|
activity.
|
|
@@ -127,25 +137,40 @@ activity.
|
|
|
127
137
|
Note that the agent runs unattended (`--yolo` by default), so it does not
|
|
128
138
|
inherit the permission prompts of whatever launched it.
|
|
129
139
|
|
|
140
|
+
`--retries N` includes the first attempt and defaults to 1. Retries reuse the
|
|
141
|
+
same task state and progress after incomplete runs, timeouts, launch errors, or
|
|
142
|
+
non-zero exits. An explicit failure or cancellation, an interruption, or a
|
|
143
|
+
failed review stops immediately. Review-only runs cannot be retried.
|
|
144
|
+
|
|
145
|
+
Concurrent writing runs must not share a checkout. Lemming stays independent of
|
|
146
|
+
Git, Mercurial, and other version control systems: the caller creates a separate
|
|
147
|
+
working copy with the repository's existing VCS, passes it with
|
|
148
|
+
`lemming -C <working-copy> -v exec ...`, and owns result recovery and cleanup.
|
|
149
|
+
For Git, stop when the source checkout has modified or untracked files instead
|
|
150
|
+
of silently excluding them. Retain every isolated working copy until its changes
|
|
151
|
+
have been recovered. The packaged skill includes a minimal Git example.
|
|
152
|
+
|
|
130
153
|
### Teaching Your Agent to Use It
|
|
131
154
|
|
|
132
155
|
Lemming ships an Agent Skill so that an agent already running — Codex, Claude
|
|
133
156
|
Code, Gemini CLI, Cursor — can reach any other agent CLI without knowing how
|
|
134
|
-
each one spells its flags. Install it
|
|
157
|
+
each one spells its flags. Install or refresh it with:
|
|
135
158
|
|
|
136
159
|
```bash
|
|
137
|
-
# Cross-tool location
|
|
160
|
+
# Cross-tool location plus every detected tool-specific location
|
|
138
161
|
lemming skill install
|
|
139
162
|
|
|
140
|
-
# Cover detected tools that require their own skill directory too
|
|
141
|
-
lemming skill install --all
|
|
142
|
-
|
|
143
163
|
# This repository only
|
|
144
164
|
lemming skill install --to .agents/skills
|
|
165
|
+
|
|
166
|
+
# Inspect every supported location
|
|
167
|
+
lemming skill status
|
|
145
168
|
```
|
|
146
169
|
|
|
147
|
-
`lemming skill uninstall` reverses
|
|
148
|
-
does not hold this skill, so a mistyped `--to` fails
|
|
170
|
+
`lemming skill uninstall` reverses the default installation sweep. Both refuse
|
|
171
|
+
to touch a directory that does not hold this skill, so a mistyped `--to` fails
|
|
172
|
+
instead of deleting work. Use `--link` on a durable installation to track
|
|
173
|
+
package upgrades without reinstalling.
|
|
149
174
|
|
|
150
175
|
---
|
|
151
176
|
|
|
@@ -187,9 +212,9 @@ loops through each pending task:
|
|
|
187
212
|
`lemming complete` or `lemming fail`. Agents can also schedule new tasks
|
|
188
213
|
with `lemming add`, breaking down complex work into smaller steps that
|
|
189
214
|
Lemming will pick up automatically.
|
|
190
|
-
4. **Retry or advance**: On failure, Lemming retries the task
|
|
191
|
-
|
|
192
|
-
previous attempts. On success, it moves to the next task.
|
|
215
|
+
4. **Retry or advance**: On failure, Lemming retries the task up to the
|
|
216
|
+
configured roadmap limit, with accumulated progress as context so the agent
|
|
217
|
+
learns from previous attempts. On success, it moves to the next task.
|
|
193
218
|
5. **Orchestration**: After each task, Lemming can run one or more
|
|
194
219
|
**Orchestrator Hooks** (like the built-in `roadmap` hook) to evaluate the
|
|
195
220
|
results and adapt the roadmap if needed. Hooks are enabled by default but
|
|
@@ -389,19 +414,21 @@ These come before the subcommand and apply to all of them.
|
|
|
389
414
|
revision range is resolved to the files it changed. Defaults to uncommitted
|
|
390
415
|
work, or the whole tree outside a repository.
|
|
391
416
|
- `--runner`, `--model`: Which agent CLI and model to use.
|
|
417
|
+
- `--retries`: Maximum total task-runner attempts, including the first
|
|
418
|
+
(default 1). Does not retry review-only runs.
|
|
392
419
|
- `--time-limit`: Minutes before the agent is killed (default 60, 0 for no
|
|
393
420
|
limit).
|
|
394
421
|
- `--yolo/--no-yolo`: Run the agent unattended (default: True).
|
|
395
422
|
- `--keep`: Keep the run's state directory even when it succeeds.
|
|
396
423
|
- **`skill install`**: Install the packaged Agent Skill so agents discover
|
|
397
|
-
Lemming. Writes to `~/.agents/skills`
|
|
398
|
-
|
|
424
|
+
Lemming. Writes to `~/.agents/skills` and every detected tool-specific
|
|
425
|
+
directory by default. Re-running it refreshes existing Lemming copies.
|
|
399
426
|
- `--to <dir>`: Install into a specific skills directory.
|
|
400
|
-
- `--all`: Also cover every detected tool's own skills directory.
|
|
401
427
|
- `--link`: Symlink instead of copying, so upgrades take effect immediately.
|
|
402
|
-
- `--force`: Replace an existing installation of this skill.
|
|
403
428
|
- `--dry-run`: Print what would happen, refusals included.
|
|
404
|
-
- **`skill uninstall`**: Remove it again.
|
|
429
|
+
- **`skill uninstall`**: Remove it again. Supports `--to` and `--dry-run`.
|
|
430
|
+
- **`skill status`**: Show every supported location and installation state.
|
|
431
|
+
Supports `--json` for structured output.
|
|
405
432
|
- **`stop`**: Stop the running loop and its runner.
|
|
406
433
|
- `--after-current-task`: Drain instead — let the running task finish, then
|
|
407
434
|
stop before claiming another. This is the safe way to change the runner or
|
|
@@ -24,6 +24,9 @@ agent run can hold.
|
|
|
24
24
|
```sh
|
|
25
25
|
lemming -v exec "Fix the flaky heartbeat test in src/runner_test.py" --runner codex
|
|
26
26
|
|
|
27
|
+
# Opt into at most three total attempts for transient runner failures
|
|
28
|
+
lemming -v exec "Fix the flaky heartbeat test" --retries 3
|
|
29
|
+
|
|
27
30
|
# Pipe a longer handoff rather than fighting shell quoting; no length limit
|
|
28
31
|
cat handoff.md | lemming -v exec -f - --runner agy
|
|
29
32
|
```
|
|
@@ -48,8 +51,70 @@ The task runner is required to record its approach first and concise findings as
|
|
|
48
51
|
it works. These entries are checkpoints rather than a continuous trace, so use
|
|
49
52
|
verbose output or the log to tell whether it is actively making progress.
|
|
50
53
|
|
|
51
|
-
The
|
|
52
|
-
|
|
54
|
+
The runner receives no conversation history and cannot be steered mid-run. Give
|
|
55
|
+
it a self-contained handoff with:
|
|
56
|
+
|
|
57
|
+
- **Goal:** the concrete outcome to produce.
|
|
58
|
+
- **Hard constraints:** scope, compatibility, process, and safety requirements.
|
|
59
|
+
- **Relevant findings and evidence:** paths, commands, output, and prior
|
|
60
|
+
observations it should rely on.
|
|
61
|
+
- **Approaches ruled out and why:** decisions it should not revisit without new
|
|
62
|
+
evidence.
|
|
63
|
+
- **Definition of done and verification:** the required result and checks that
|
|
64
|
+
prove it works.
|
|
65
|
+
|
|
66
|
+
For example:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
lemming -v exec -f - --runner codex <<'EOF'
|
|
70
|
+
# Goal
|
|
71
|
+
Fix the race that lets two workers claim the same queued job.
|
|
72
|
+
|
|
73
|
+
# Hard constraints
|
|
74
|
+
- Keep the SQLite schema and public CLI unchanged.
|
|
75
|
+
- Make the smallest scoped change; do not reformat unrelated files.
|
|
76
|
+
|
|
77
|
+
# Relevant findings and evidence
|
|
78
|
+
- `uv run pytest tests/test_queue.py -k concurrent_claim` fails intermittently.
|
|
79
|
+
- `src/queue.py:claim_next` reads and updates in separate transactions.
|
|
80
|
+
|
|
81
|
+
# Approaches ruled out and why
|
|
82
|
+
- Do not add an in-process mutex; separate worker processes would bypass it.
|
|
83
|
+
|
|
84
|
+
# Definition of done and verification
|
|
85
|
+
- The concurrency test passes repeatedly and no existing behavior regresses.
|
|
86
|
+
- Run the focused test, then the full test suite and configured linter.
|
|
87
|
+
EOF
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Isolate concurrent writing runs
|
|
91
|
+
|
|
92
|
+
Concurrent writing runs must use separate working copies. Detect and use the
|
|
93
|
+
repository's existing version control system, then pass each copy with the
|
|
94
|
+
global `-C` option. The caller owns creation, result recovery, and cleanup;
|
|
95
|
+
Lemming remains independent of Git, Mercurial, and other VCSs.
|
|
96
|
+
|
|
97
|
+
For Git, refuse modified or untracked input rather than silently excluding it,
|
|
98
|
+
then create a worktree from committed `HEAD`:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
repo=$(git rev-parse --show-toplevel) || exit 1
|
|
102
|
+
test -z "$(git -C "$repo" status --porcelain)" || exit 1
|
|
103
|
+
worktree=$(mktemp -d "${TMPDIR:-/tmp}/lemming-exec.XXXXXX") || exit 1
|
|
104
|
+
branch="lemming/$(basename "$worktree")"
|
|
105
|
+
git -C "$repo" worktree add -b "$branch" "$worktree" HEAD || exit 1
|
|
106
|
+
printf 'Worktree: %s\nBranch: %s\n' "$worktree" "$branch"
|
|
107
|
+
lemming -C "$worktree" -v exec "<self-contained task>" --runner codex
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Retain the reported worktree after success, failure, timeout, or interruption.
|
|
111
|
+
After its changes have been committed, copied, or deliberately discarded, use
|
|
112
|
+
Git's non-forcing cleanup so dirty or unmerged work is not destroyed:
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
git -C "$repo" worktree remove "$worktree"
|
|
116
|
+
git -C "$repo" branch -d "$branch"
|
|
117
|
+
```
|
|
53
118
|
|
|
54
119
|
## Run a review
|
|
55
120
|
|
|
@@ -111,12 +176,14 @@ one off for the project.
|
|
|
111
176
|
- **The agent runs unattended.** `--yolo` is the default, so it does not inherit
|
|
112
177
|
the permission prompts of whatever launched it. Treat this as granting an
|
|
113
178
|
agent unsupervised write access to the working directory.
|
|
114
|
-
- **`exec` makes one attempt
|
|
115
|
-
|
|
179
|
+
- **`exec` makes one attempt by default.** `--retries N` opts into at most `N`
|
|
180
|
+
total task attempts with progress carried forward. Explicit failure,
|
|
181
|
+
cancellation, interruption, and failed reviews stop immediately.
|
|
116
182
|
- **Interrupting leaves partial edits.** Nothing is restored, so there is no
|
|
117
183
|
atomicity to rely on.
|
|
118
184
|
- **Concurrent runs in one checkout interleave their edits.** Give each writing
|
|
119
|
-
run its own
|
|
185
|
+
run its own VCS-managed working copy and address it with `-C`; retain the copy
|
|
186
|
+
until its result is recovered.
|
|
120
187
|
- **Every run reports its state.** The tasks file and task ID are printed on
|
|
121
188
|
stderr at startup. Successful state is removed on exit unless `--keep` is
|
|
122
189
|
used; failures keep their directory and print it again for recovery. Kept
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "lemming-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
8
8
|
description = "An autonomous, iterative task runner for AI coding agents."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -16,6 +16,7 @@ keywords = ["ai", "agents", "automation", "antigravity", "claude", "opencode"]
|
|
|
16
16
|
dependencies = [
|
|
17
17
|
"beautifulsoup4>=4.13.3",
|
|
18
18
|
"click>=8.0.0",
|
|
19
|
+
"click-agentcli>=0.3.0",
|
|
19
20
|
"fastapi>=0.124.4",
|
|
20
21
|
"markdownify>=0.14.1",
|
|
21
22
|
"pydantic>=2.12.5",
|
|
@@ -30,6 +30,9 @@ ALL_REVIEWS = "all"
|
|
|
30
30
|
# large enough that reading it whole is wasteful.
|
|
31
31
|
MAX_LOG_TAIL_BYTES = 256 * 1024
|
|
32
32
|
|
|
33
|
+
# Log header used to isolate the final runner or review output.
|
|
34
|
+
ATTEMPT_HEADER = "--- Attempt started at "
|
|
35
|
+
|
|
33
36
|
|
|
34
37
|
def _read_log_tail(
|
|
35
38
|
log_file: pathlib.Path, max_bytes: int = MAX_LOG_TAIL_BYTES
|
|
@@ -41,17 +44,20 @@ def _read_log_tail(
|
|
|
41
44
|
max_bytes: Most bytes to read from the end of the file.
|
|
42
45
|
|
|
43
46
|
Returns:
|
|
44
|
-
The
|
|
47
|
+
The final attempt within the decoded tail. A leading partial line is
|
|
45
48
|
harmless: the extractor skips anything that is not a whole event.
|
|
46
49
|
"""
|
|
47
50
|
try:
|
|
48
51
|
with open(log_file, "rb") as f:
|
|
49
52
|
f.seek(0, 2)
|
|
50
53
|
f.seek(max(0, f.tell() - max_bytes))
|
|
51
|
-
|
|
54
|
+
text = f.read().decode("utf-8", errors="replace")
|
|
52
55
|
except OSError:
|
|
53
56
|
return ""
|
|
54
57
|
|
|
58
|
+
header = text.rfind(ATTEMPT_HEADER)
|
|
59
|
+
return text[header:] if header >= 0 else text
|
|
60
|
+
|
|
55
61
|
|
|
56
62
|
def _resolve_prompt(description: str | None, file: typing.TextIO | None) -> str:
|
|
57
63
|
"""Returns the prompt text from an argument or a file.
|
|
@@ -237,6 +243,13 @@ def _task_status(
|
|
|
237
243
|
default=60,
|
|
238
244
|
help="Minutes before the agent is killed (0 disables the limit).",
|
|
239
245
|
)
|
|
246
|
+
@click.option(
|
|
247
|
+
"--retries",
|
|
248
|
+
default=1,
|
|
249
|
+
type=click.IntRange(min=1),
|
|
250
|
+
show_default=True,
|
|
251
|
+
help="Maximum total task-runner attempts, including the first.",
|
|
252
|
+
)
|
|
240
253
|
@click.option(
|
|
241
254
|
"--yolo/--no-yolo",
|
|
242
255
|
default=True,
|
|
@@ -258,6 +271,7 @@ def exec_command(
|
|
|
258
271
|
runner_name: str | None,
|
|
259
272
|
model_name: str | None,
|
|
260
273
|
time_limit: int,
|
|
274
|
+
retries: int,
|
|
261
275
|
yolo: bool,
|
|
262
276
|
keep: bool,
|
|
263
277
|
runner_args: tuple,
|
|
@@ -285,6 +299,10 @@ def exec_command(
|
|
|
285
299
|
if description or file or not reviews
|
|
286
300
|
else None
|
|
287
301
|
)
|
|
302
|
+
if prompt is None and retries > 1:
|
|
303
|
+
raise click.UsageError(
|
|
304
|
+
"--retries only applies when exec has a task description."
|
|
305
|
+
)
|
|
288
306
|
|
|
289
307
|
# The runner must edit the caller's workspace, never the throwaway
|
|
290
308
|
# directory that only holds this run's bookkeeping.
|
|
@@ -304,9 +322,8 @@ def exec_command(
|
|
|
304
322
|
return
|
|
305
323
|
scope_text = scope.describe(entries)
|
|
306
324
|
|
|
307
|
-
#
|
|
308
|
-
|
|
309
|
-
config = tasks.RoadmapConfig(retries=1, time_limit=time_limit)
|
|
325
|
+
# Extra attempts require opt-in because each can incur runner cost.
|
|
326
|
+
config = tasks.RoadmapConfig(retries=retries, time_limit=time_limit)
|
|
310
327
|
if runner_name:
|
|
311
328
|
config.runner = runner_name
|
|
312
329
|
if model_name:
|