coderio 0.4.1__tar.gz → 0.4.3__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.
- {coderio-0.4.1 → coderio-0.4.3}/CHANGELOG.md +118 -2
- coderio-0.4.3/PKG-INFO +148 -0
- coderio-0.4.3/README.md +103 -0
- coderio-0.4.3/README_en.md +103 -0
- {coderio-0.4.1 → coderio-0.4.3}/pyproject.toml +7 -7
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/_deepagents_compat.py +39 -10
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/deep_loop.py +41 -6
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/hooks.py +75 -15
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/app.py +18 -3
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/repl.py +9 -3
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/run_cmd.py +111 -27
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/config/loader.py +25 -14
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/config/models.py +7 -1
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/config/trust.py +124 -21
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/models.py +9 -3
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/command_policy.py +95 -25
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/sandbox_runner.py +11 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/win_sandbox.py +0 -4
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_deepagents_compat.py +90 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_hooks.py +116 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_run_cmd.py +112 -5
- coderio-0.4.3/tests/config/test_trust.py +379 -0
- coderio-0.4.3/tests/test_seams.py +894 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_command_policy.py +36 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_sandbox.py +99 -0
- {coderio-0.4.1 → coderio-0.4.3}/uv.lock +1 -1
- coderio-0.4.1/PKG-INFO +0 -523
- coderio-0.4.1/README.md +0 -475
- coderio-0.4.1/README_en.md +0 -478
- coderio-0.4.1/tests/config/test_trust.py +0 -158
- {coderio-0.4.1 → coderio-0.4.3}/.github/dependabot.yml +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/.github/workflows/ci.yml +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/.github/workflows/release.yml +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/.gitignore +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/CONTRIBUTING.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/LICENSE +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/THIRD_PARTY_LICENSES.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/docs/coderio-architecture.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/scripts/verify_deepagent_live.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/scripts/verify_harness_live.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/command_review.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/harness.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/harness_middleware.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/permission_middleware.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/prompts.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/skill_tool.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/state.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/agent/stream.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/commands.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/credentials.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/mcp_cmd.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/multimodal.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/onboarding.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/providers.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/render.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/skills_cmd.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/stream.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/tui.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/tui_onboarding.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/tui_screens.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/cli/tui_widgets.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/config/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/config/bootstrap.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/llm/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/llm/factory.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/llm/probe.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/mcp_loader.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/session/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/session/message.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/session/store.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/bundled/executing-plans/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/LICENSE +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/README.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/clarifying-questions/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/clarifying-questions/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/code-review/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/code-review/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/commit-message/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/commit-message/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/debugging/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/debugging/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/error-handling/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/error-handling/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/lion-writing-skills/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/lion-writing-skills/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/naming/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/naming/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/onboarding-unknown-codebase/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/onboarding-unknown-codebase/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/spec-writing/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/spec-writing/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/task-breakdown/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/task-breakdown/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/testing/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/testing/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/verify-and-fix/SKILL.md +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/lion-skills/skills/verify-and-fix/evals/evals.json +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/parser.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/skills/store.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/base.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/bash.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/edit_file.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/glob_tool.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/grep_tool.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/linux_sandbox.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/list_dir.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/multi_edit.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/note.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/permission.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/read_file.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/todo.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/web_fetch.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/web_search.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/win_job.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/src/coderio/tools/write_file.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/conftest.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_command_review.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_deep_integration.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_deep_loop.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_deep_loop_unit.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_harness.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_harness_middleware.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_perf_baseline.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_prompts.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_skill_tool.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_state.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/agent/test_stream.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_app.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_command_menu.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_commands.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_credentials.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_input_isolation.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_live_thinking.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_mcp_cmd.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_multimodal.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_onboarding.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_onboarding_logic.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_providers.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_render.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_repl_loop.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_repl_reset.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_skills_cmd.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_status_bar.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_stream.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_truncation.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_tui_onboarding.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_tui_picker.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_tui_screens.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_tui_startup.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_tui_widgets.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/cli/test_ux_features.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/config/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/config/test_bootstrap.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/config/test_loader.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/config/test_models.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/conftest.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/e2e/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/llm/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/llm/test_factory.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/llm/test_probe.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/session/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/session/test_message.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/session/test_store.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/skills/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/skills/test_bundled.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/skills/test_parser.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/skills/test_skill_tools.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/skills/test_store.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/test_mcp_loader.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/test_p0_stability.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/test_repl.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/test_version.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/__init__.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_bash.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_concrete_gates.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_edit_prefix.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_file_tools.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_glob_tool.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_grep_tool.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_list_dir.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_multi_edit.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_note.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_permission.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_registry.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_search_tools.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_todo.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_web.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_web_fetch.py +0 -0
- {coderio-0.4.1 → coderio-0.4.3}/tests/tools/test_win_job.py +0 -0
|
@@ -6,6 +6,124 @@ All notable changes to coderio are documented here. The format follows
|
|
|
6
6
|
`pyproject.toml`'s `[project].version` — `coderio.__version__` reads it via
|
|
7
7
|
`importlib.metadata`.
|
|
8
8
|
|
|
9
|
+
## [0.4.3] — 2026-08-21
|
|
10
|
+
|
|
11
|
+
### Security — P1/P2 hardening (audit-verified, adversarial + mutation tested)
|
|
12
|
+
- **command_policy**: replaced fragile `_RM_RECURSIVE_PREFIX` regex (failed on
|
|
13
|
+
`rm -fr /` and `--recursive --force`) with Python-level `_check_recursive_rm()`
|
|
14
|
+
that tokenizes the command and correctly detects recursive flags in any order.
|
|
15
|
+
All flag permutations now blocked: `rm -rf /`, `rm -fr /`, `rm -r -f /`,
|
|
16
|
+
`rm --recursive --force /`, `rm --RECURSIVE /`, `rm -rf ~/`, `rm -rf $HOME/`,
|
|
17
|
+
`rm -rf *`. False positives eliminated: `rm -f /etc/passwd`, `rm --Force /`,
|
|
18
|
+
`echo rm -rf /`.
|
|
19
|
+
- **win_sandbox**: reverted `_dict_to_env_block` env-forwarding plumbing that
|
|
20
|
+
broke `CreateProcessAsUserW` on Win32. `lpEnvironment=None` preserves parent
|
|
21
|
+
env inheritance (safest path). Known limitation documented for future work.
|
|
22
|
+
- **loader**: `_find_project_dir` now accepts `str | Path` (CLI may pass str).
|
|
23
|
+
- **test_seams**: new 22-test seam suite covering command_policy↔middleware,
|
|
24
|
+
loader↔repl↔skills, deep_loop↔sandbox_runner↔win_sandbox boundaries.
|
|
25
|
+
All existing tests (884 passed) + seams (22 passed) green.
|
|
26
|
+
|
|
27
|
+
## [0.4.2] — 2026-08-18
|
|
28
|
+
|
|
29
|
+
### Security — v3 audit short-term batch (#7/#8/#9/#11/#14, all runtime-verified)
|
|
30
|
+
- **#7 · headless default permission full → plan**: a headless entry that
|
|
31
|
+
silently allowed everything was a zero-confirmation door. `coderio run` now
|
|
32
|
+
defaults to read-only plan; full requires the explicit
|
|
33
|
+
`--dangerously-skip-permissions` flag (Claude Code's name for the same
|
|
34
|
+
escape hatch). confirm/auto_edit fail fast without a TTY (the gate is lazy,
|
|
35
|
+
so input() would otherwise EOFError mid-execution); invalid --permission
|
|
36
|
+
values are rejected up front.
|
|
37
|
+
- **#8 · project-layer skills join the trust gate**: a repo shipping ONLY
|
|
38
|
+
`.coderio/skills` previously loaded them with zero confirmation — yet skills
|
|
39
|
+
enter the system prompt and may carry tools.py that exec's on activation.
|
|
40
|
+
Skills now participate in discovery + content fingerprint (per-file hash;
|
|
41
|
+
any skill edit re-triggers the prompt), and the confirmation summary marks
|
|
42
|
+
skills carrying tools.py with "⚠ executes code". tools.py load failures are
|
|
43
|
+
logged, no longer silent.
|
|
44
|
+
- **#9 · trust store hardening**: the store gets owner-only permissions
|
|
45
|
+
(POSIX 0600 / Windows icacls, reusing the credentials helper); a corrupt
|
|
46
|
+
store is left untouched instead of being reset (the old reset destroyed
|
|
47
|
+
every other repo's trust entries); `SandboxFsConfig.deny_write` now
|
|
48
|
+
defaults to `["~/.coderio"]` so sandboxed commands can't rewrite the
|
|
49
|
+
config/credentials/trust store (explicit `deny_write = []` opts out;
|
|
50
|
+
Linux bwrap only — Windows sandbox is a no-op today).
|
|
51
|
+
- **#11 · research subagent execution-time enforcement**: PermissionMiddleware
|
|
52
|
+
+ CommandReviewMiddleware now ride the research subagent (the tool
|
|
53
|
+
whitelist filters what the model SEES; these gate what actually RUNS).
|
|
54
|
+
Failover direction reversed: a whitelist that cannot be constructed — or
|
|
55
|
+
fails at runtime — degrades to a DENY-ALL middleware (zero tools), not to
|
|
56
|
+
the old no-middleware state that inherited every tool including
|
|
57
|
+
write/execute.
|
|
58
|
+
- **#14 · headless wall-clock timeout + exit codes**: `--timeout <seconds>`
|
|
59
|
+
(thread+join; SIGALRM doesn't exist on Windows) exits 124 on expiry;
|
|
60
|
+
agent execution failures exit 2 (distinct from config errors' 1); success
|
|
61
|
+
0. Documented in README for CI use.
|
|
62
|
+
|
|
63
|
+
### Fixed — hooks completion (2026-08-14 v3 audit P1/P2 items)
|
|
64
|
+
- **Timeout latency (v3 P1: timeout=2 hook took 12s)**: the post-kill pipe
|
|
65
|
+
drain waited 10s for an EOF that never comes on Windows (a pre-kill
|
|
66
|
+
grandchild holds the write end) — and the drained output was never consumed
|
|
67
|
+
anyway (hardcoded empty return). Now a 1s grace then abandon: a timeout=2
|
|
68
|
+
hook returns in ~3s. Windows grandchild leak documented as a known
|
|
69
|
+
limitation (the turn is no longer hostage; root fix = CREATE_SUSPENDED +
|
|
70
|
+
pre-assigned Job + stdin pipe through _create_process_with_token). Latency
|
|
71
|
+
regression test added (`elapsed < timeout + 2`), mutation-verified.
|
|
72
|
+
- **Per-event budget (v3 P1: N hooks × 60s on every tool call)**: fire() now
|
|
73
|
+
enforces a 30s total budget per event (overridable on HookRunner for
|
|
74
|
+
tests). Each hook's timeout tightens to min(spec.timeout, budget
|
|
75
|
+
remaining); exhaustion skips the remaining hooks with an error note
|
|
76
|
+
(fail-open, consistent with the module's positioning).
|
|
77
|
+
- **Subagents bypassed hooks (v3 #12)**: research and general-purpose
|
|
78
|
+
subagents both carry HooksMiddleware now (outermost, same order as the main
|
|
79
|
+
agent) — task() delegation can no longer sidestep PreToolUse/PostToolUse.
|
|
80
|
+
No middleware overhead when no hooks are configured.
|
|
81
|
+
- **Repo [[hooks]] silently dropped user hooks (v3 P2)**: _merge replaces
|
|
82
|
+
lists wholesale, so a repo's hooks config wiped the user's protective
|
|
83
|
+
hooks. Hooks now APPEND across layers — user hooks first (first-blocker-
|
|
84
|
+
wins: the user's deny reason is what the model sees). The first and only
|
|
85
|
+
list-merge in the loader; every other key keeps replace semantics.
|
|
86
|
+
- +7 tests (latency guard, budget skip/tighten, subagent middleware stacks ×3,
|
|
87
|
+
merge order). Mutation check: reintroducing the 10s drain turns the latency
|
|
88
|
+
test red (10.1s ≥ 4s bound) — the guard actually guards.
|
|
89
|
+
|
|
90
|
+
### Fixed — 2026-08-18 self-audit (3 bugs + 3 warnings, all runtime-verified)
|
|
91
|
+
- **BUG A · `--permission full` had no flag gate (claim vs code mismatch)**:
|
|
92
|
+
the 0.4.1 commit message and CHANGELOG claimed "full requires
|
|
93
|
+
--dangerously-skip-permissions" — no such gate existed; `--permission full`
|
|
94
|
+
alone ran with full access (verified end-to-end by an audit agent that
|
|
95
|
+
unintentionally ran three real model turns through it). The gate is real
|
|
96
|
+
now: full without the flag exits 1. +2 tests (negative and positive sides).
|
|
97
|
+
Fourth seam-class failure in project history (v1: deepagents↔coderio; v3:
|
|
98
|
+
config↔runtime, trust↔mcp_loader; this: message↔code) — new rule in the
|
|
99
|
+
audit report: every behavior claim in a commit message must have a
|
|
100
|
+
corresponding verified command output before release.
|
|
101
|
+
- **BUG B · Windows NUL bypassed the confirm-mode TTY check**: `</dev/null`
|
|
102
|
+
(the classic CI idiom) makes `sys.stdin.isatty()` return True on Windows
|
|
103
|
+
(MSVCRT treats character devices as ttys) — the check passed, then
|
|
104
|
+
`input()` read NUL, EOFError'd, and crashed the agent mid-execution.
|
|
105
|
+
confirm/auto_edit are no longer valid headless values AT ALL (rejected
|
|
106
|
+
unconditionally); the interactive TUI is the only prompting surface.
|
|
107
|
+
- **BUG C · the deny_write default was dead config for most users**:
|
|
108
|
+
SandboxFsConfig's `deny_write=["~/.coderio"]` default only applied when the
|
|
109
|
+
`[tools.sandbox_filesystem]` table EXISTED — users without the table got
|
|
110
|
+
fs_config=None, and bwrap's built-in layout had no deny_write, so sandboxed
|
|
111
|
+
commands could write ~/.coderio (config/credentials/TRUST STORE). The
|
|
112
|
+
sandbox runner now constructs the default config when fs_config is None;
|
|
113
|
+
explicit user configs (including `deny_write = []`) pass through unchanged.
|
|
114
|
+
- **hooks budget skip-count was dead code**: `self.specs[len(self.specs):]`
|
|
115
|
+
is always the empty slice, so the "N hook(s) skipped" message always
|
|
116
|
+
printed "remaining" — the count never appeared (and no test asserted it).
|
|
117
|
+
Fixed with enumerate-indexed slicing (verified: 4 hooks skipped →
|
|
118
|
+
"4 hook(s) skipped").
|
|
119
|
+
- **trust store `null` slipped the corruption guard**: JSON `null` parsed to
|
|
120
|
+
None and bypassed the `is not None` shape check, getting overwritten. All
|
|
121
|
+
non-dict JSON (including null) now leaves the store untouched.
|
|
122
|
+
- **nested typer.Exit produced a misleading second error line**: typer.Exit
|
|
123
|
+
is a RuntimeError subclass, so the session-load failure's clean exit was
|
|
124
|
+
re-caught by "Runtime setup failed" and printed twice. Nested exits now
|
|
125
|
+
pass through with their original code and message.
|
|
126
|
+
|
|
9
127
|
## [0.4.1] — 2026-08-17
|
|
10
128
|
|
|
11
129
|
### Added
|
|
@@ -67,8 +185,6 @@ All notable changes to coderio are documented here. The format follows
|
|
|
67
185
|
solely on the token stream; a non-streamed final message vanished. The
|
|
68
186
|
final result is now always printed (after a separator in non-quiet mode).
|
|
69
187
|
|
|
70
|
-
## [Unreleased]
|
|
71
|
-
|
|
72
188
|
## [0.4.0] — 2026-08-17
|
|
73
189
|
|
|
74
190
|
### Added
|
coderio-0.4.3/PKG-INFO
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: coderio
|
|
3
|
+
Version: 0.4.3
|
|
4
|
+
Summary: A skill-driven coding agent — structural harness, foldable thinking TUI, deepagents engine.
|
|
5
|
+
Author: coderio contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: agent,ai-agent,cli,coding-agent,langchain,langgraph,llm,mcp,model-context-protocol,sandbox,skills,textual,tui
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: ddgs>=4.0
|
|
22
|
+
Requires-Dist: deepagents>=0.6
|
|
23
|
+
Requires-Dist: httpx>=0.27
|
|
24
|
+
Requires-Dist: langchain-anthropic>=0.2
|
|
25
|
+
Requires-Dist: langchain-core>=0.3
|
|
26
|
+
Requires-Dist: langchain-openai>=0.2
|
|
27
|
+
Requires-Dist: langchain>=0.3
|
|
28
|
+
Requires-Dist: langgraph-checkpoint-sqlite>=2.0
|
|
29
|
+
Requires-Dist: langgraph>=0.2
|
|
30
|
+
Requires-Dist: pydantic>=2
|
|
31
|
+
Requires-Dist: rich>=13
|
|
32
|
+
Requires-Dist: textual>=0.40
|
|
33
|
+
Requires-Dist: tomli-w>=1.0
|
|
34
|
+
Requires-Dist: typer>=0.12
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
37
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest-cov>=4; extra == 'dev'
|
|
40
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
41
|
+
Requires-Dist: ruff>=0.16; extra == 'dev'
|
|
42
|
+
Provides-Extra: mcp
|
|
43
|
+
Requires-Dist: langchain-mcp-adapters>=0.3.2; extra == 'mcp'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# coderio
|
|
47
|
+
|
|
48
|
+
[中文](README.md) | **English**
|
|
49
|
+
|
|
50
|
+
> The agent claims "done" without running the tests? coderio's harness stops it.
|
|
51
|
+
> A local coding agent with **native Zhipu GLM & StepFun Step coding-plan support** — four-tier permissions, layered sandbox, MCP, lifecycle hooks, and an interactive TUI.
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install coderio
|
|
59
|
+
coderio # onboarding wizard on first launch (pick provider, paste API key, auto context-window probe)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Requires Python 3.11+; Git Bash on Windows. Linux / macOS supported.
|
|
63
|
+
|
|
64
|
+
## Why coderio
|
|
65
|
+
|
|
66
|
+
The shared weakness of coding agents: **the model says "I'm done" and you just have to trust it**. coderio turns that sentence into a structural constraint—
|
|
67
|
+
|
|
68
|
+
### The Four Gates: the agent can't lie to you
|
|
69
|
+
|
|
70
|
+
| Gate | Behavior |
|
|
71
|
+
|---|---|
|
|
72
|
+
| **VerifyGate** | Wrote code, never ran it, wants to finish → intercepted, forced to continue. Parses real exit codes — **a failing test run does NOT count as verified** |
|
|
73
|
+
| **CompletionGate** | Declares done with pending todos → intercepted |
|
|
74
|
+
| **GroundingGate** | Cites files it never read → intercepted |
|
|
75
|
+
| **PlanGate** | Writes code without a todo list → soft nudge |
|
|
76
|
+
|
|
77
|
+
Not a prompt-level soft rule — a system-level control based on tool-call ground truth. Claude Code and Codex don't have this.
|
|
78
|
+
|
|
79
|
+
### Native Chinese coding-plan support
|
|
80
|
+
|
|
81
|
+
Zhipu **GLM Coding Plan** and StepFun **Step Plan** work out of the box (direct Anthropic-protocol connection) — your subscription quota runs a local agent, no proxies, no middle layer. Also supports OpenAI / Anthropic / Ollama / any OpenAI-compatible endpoint, with multi-profile switching.
|
|
82
|
+
|
|
83
|
+
### Layered security, honestly stated
|
|
84
|
+
|
|
85
|
+
- Four permission tiers (plan read-only / confirm per-action / auto_edit / full)
|
|
86
|
+
- Command blacklist + whitelist (accident prevention); Linux bubblewrap OS sandbox (boundary enforcement)
|
|
87
|
+
- First-use repo-config trust confirmation (hostile-repo protection); web_fetch SSRF protection
|
|
88
|
+
- The blacklist/whitelist are **accident prevention, not adversarial defense** — adversarial protection comes from the sandbox + permissions; use a VM for hostile code
|
|
89
|
+
|
|
90
|
+
## Feature highlights
|
|
91
|
+
|
|
92
|
+
- **Interactive TUI**: streaming output, foldable thinking (Ctrl+O), collapsible TODO panel, vertical permission menu, task interruption (Esc), slash-command autocomplete, session management
|
|
93
|
+
- **Headless mode**: `coderio run "task"` one-shot execution (CI / scripts / benchmarks) with graded exit codes
|
|
94
|
+
- **MCP support**: connect external tools via `.mcp.json` (Claude Code-compatible format), managed with `coderio mcp`
|
|
95
|
+
- **Lifecycle hooks**: `[[hooks]]` run your commands at PreToolUse / PostToolUse / UserPromptSubmit (exit 2 = block) — IO contract compatible with Claude Code
|
|
96
|
+
- **Three-layer skills**: bundled + user + project, progressive disclosure saves context
|
|
97
|
+
- **Context governance**: auto-compaction (60% window trigger), large-block offload, sqlite checkpoints across turns
|
|
98
|
+
- **Subagents**: research (read-only, double-enforced) + general-purpose (inherits the main agent's full security stack)
|
|
99
|
+
- **Engineering discipline**: 850+ tests, 80% coverage, mypy hard gate, uv.lock, 3 OS × 2 Python CI matrix
|
|
100
|
+
|
|
101
|
+
<details>
|
|
102
|
+
<summary><b>Config example</b> (click to expand)</summary>
|
|
103
|
+
|
|
104
|
+
```toml
|
|
105
|
+
# ~/.coderio/config.toml
|
|
106
|
+
[model]
|
|
107
|
+
provider_id = "bigmodel_coding_plan" # Zhipu/StepFun coding plan, or openai/anthropic/ollama/custom
|
|
108
|
+
default = "glm-5.2"
|
|
109
|
+
|
|
110
|
+
[tools]
|
|
111
|
+
permission_mode = "confirm" # plan | confirm | auto_edit | full
|
|
112
|
+
sandbox_mode = "off" # off | job (resource limits) | write (Linux file-write isolation)
|
|
113
|
+
|
|
114
|
+
# Lifecycle hooks (Claude Code-compatible contract)
|
|
115
|
+
[[hooks]]
|
|
116
|
+
event = "PreToolUse"
|
|
117
|
+
matcher = "write_file|edit_file"
|
|
118
|
+
command = "python .hooks/protect.py" # JSON on stdin; exit 2 = block
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
MCP, the sandbox 4-tuple, and more: [docs/coderio-architecture.md](docs/coderio-architecture.md).
|
|
122
|
+
|
|
123
|
+
</details>
|
|
124
|
+
|
|
125
|
+
## Common commands
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
coderio # interactive TUI
|
|
129
|
+
coderio run "fix the failing test" --quiet # headless one-shot
|
|
130
|
+
coderio run "task" --dangerously-skip-permissions # full access (explicit opt-in)
|
|
131
|
+
coderio mcp add github --type http --url ... # manage MCP
|
|
132
|
+
coderio skills install # install skill suites
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Type `/` inside the TUI for all commands (/resume sessions, /mode permissions, /profile configs, /think unfold reasoning).
|
|
136
|
+
|
|
137
|
+
## Known limitations
|
|
138
|
+
|
|
139
|
+
- The Windows write-sandbox currently equals job mode (true isolation awaits the ACL work — documented honestly)
|
|
140
|
+
- Blacklist/whitelist are accident-prevention by design (regex can be bypassed by obfuscation); use the sandbox / a VM for adversarial scenarios
|
|
141
|
+
|
|
142
|
+
## Origin
|
|
143
|
+
|
|
144
|
+
A spare-time project, open-sourced as a working reference for developers building their own coding agents. The name is **code + rio** (the author's English name is Lion; "codelion" sounded odd).
|
|
145
|
+
|
|
146
|
+
## Contributing & License
|
|
147
|
+
|
|
148
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). MIT License.
|
coderio-0.4.3/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# coderio
|
|
2
|
+
|
|
3
|
+
**中文** | [English](README_en.md)
|
|
4
|
+
|
|
5
|
+
> 写了代码没跑过测试就说"完成"?coderio 的 harness 会拦住它。
|
|
6
|
+
> 一个**原生支持智谱 GLM / 阶跃 StepFun Coding Plan** 的本地 coding agent——四级权限、多层沙箱、MCP、生命周期 hooks、交互式 TUI。
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
## 安装
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install coderio
|
|
14
|
+
coderio # 首次启动进入 onboarding 向导(选 provider、填 API key、自动探测上下文窗口)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
要求:Python 3.11+;Windows 需 Git Bash。支持 Linux / macOS。
|
|
18
|
+
|
|
19
|
+
## 为什么是 coderio
|
|
20
|
+
|
|
21
|
+
市面上 coding agent 的共同软肋:**模型说"我做完了",你就得信**。coderio 把这句话变成了结构约束——
|
|
22
|
+
|
|
23
|
+
### 四道门:agent 骗不了你
|
|
24
|
+
|
|
25
|
+
| 门 | 行为 |
|
|
26
|
+
|---|---|
|
|
27
|
+
| **VerifyGate** | 写了代码没跑验证就想结束 → 拦截、强制续跑。解析真实 exit code,**测试失败不算验证通过** |
|
|
28
|
+
| **CompletionGate** | TODO 没清完就宣布完成 → 拦截 |
|
|
29
|
+
| **GroundingGate** | 引用从未读过的文件下结论 → 拦截 |
|
|
30
|
+
| **PlanGate** | 没 TODO 就动手写码 → 软提醒 |
|
|
31
|
+
|
|
32
|
+
不是提示词软规则,是基于工具调用 ground truth 的系统级控制。Claude Code / Codex 都没有这个。
|
|
33
|
+
|
|
34
|
+
### 原生支持中文 Coding Plan
|
|
35
|
+
|
|
36
|
+
智谱 **GLM Coding Plan** 和阶跃 **StepFun Step Plan** 开箱即用(Anthropic 协议直连)——你的订阅额度跑本地 agent,不需要转发、不需要中间层。同时支持 OpenAI / Anthropic / Ollama / 任意 OpenAI 兼容端点,多 profile 一键切换。
|
|
37
|
+
|
|
38
|
+
### 多层安全,诚实声明
|
|
39
|
+
|
|
40
|
+
- 四级权限(plan 只读 / confirm 逐项确认 / auto_edit / full)
|
|
41
|
+
- 命令黑名单 + 白名单(防手滑);Linux bubblewrap OS 级沙箱(防越界写)
|
|
42
|
+
- 仓库配置首次信任确认(防克隆恶意仓库);web_fetch SSRF 防护
|
|
43
|
+
- 黑白名单是**防手滑不是防对抗**——对抗性防护靠沙箱 + 权限,恶意代码请用 VM
|
|
44
|
+
|
|
45
|
+
## 特性一览
|
|
46
|
+
|
|
47
|
+
- **交互式 TUI**:流式输出、思考折叠(Ctrl+O)、可折叠 TODO 面板、纵向权限菜单、任务中断(Esc)、slash 命令补全、会话管理
|
|
48
|
+
- **headless 模式**:`coderio run "任务"` 单次运行(CI / 脚本 / benchmark),退出码分级
|
|
49
|
+
- **MCP 支持**:`.mcp.json`(Claude Code 兼容格式)接入外部工具,`coderio mcp` 命令行管理
|
|
50
|
+
- **生命周期 hooks**:`[[hooks]]` 在 PreToolUse / PostToolUse / UserPromptSubmit 等事件执行你的命令(exit 2 = 阻断),IO 契约与 Claude Code 兼容
|
|
51
|
+
- **skills 三层加载**:bundled + 用户 + 项目层,渐进披露省上下文
|
|
52
|
+
- **上下文治理**:自动压缩(60% 窗口触发)、大块 offload、sqlite 检查点跨轮持久化
|
|
53
|
+
- **子 agent**:research(只读,双重强制)+ general-purpose(继承主 agent 全部安全层)
|
|
54
|
+
- **工程纪律**:850+ 测试、80% 覆盖率、mypy 硬门、uv.lock 锁定、3 OS × 2 Python CI 矩阵
|
|
55
|
+
|
|
56
|
+
<details>
|
|
57
|
+
<summary><b>配置示例</b>(点击展开)</summary>
|
|
58
|
+
|
|
59
|
+
```toml
|
|
60
|
+
# ~/.coderio/config.toml
|
|
61
|
+
[model]
|
|
62
|
+
provider_id = "bigmodel_coding_plan" # 智谱/阶跃 coding plan,或 openai/anthropic/ollama/自定义
|
|
63
|
+
default = "glm-5.2"
|
|
64
|
+
|
|
65
|
+
[tools]
|
|
66
|
+
permission_mode = "confirm" # plan | confirm | auto_edit | full
|
|
67
|
+
sandbox_mode = "off" # off | job(资源限制)| write(Linux 文件写隔离)
|
|
68
|
+
|
|
69
|
+
# 生命周期 hooks(Claude Code 兼容契约)
|
|
70
|
+
[[hooks]]
|
|
71
|
+
event = "PreToolUse"
|
|
72
|
+
matcher = "write_file|edit_file"
|
|
73
|
+
command = "python .hooks/protect.py" # stdin 收 JSON;exit 2 = 阻断
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
MCP、沙箱四元组、更多配置见 [docs/coderio-architecture.md](docs/coderio-architecture.md)。
|
|
77
|
+
|
|
78
|
+
</details>
|
|
79
|
+
|
|
80
|
+
## 常用命令
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
coderio # 交互式 TUI
|
|
84
|
+
coderio run "修复失败的测试" --quiet # headless 单次
|
|
85
|
+
coderio run "任务" --dangerously-skip-permissions # full 权限(显式选择)
|
|
86
|
+
coderio mcp add github --type http --url ... # 管理 MCP
|
|
87
|
+
coderio skills install # 安装 skill 套件
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
TUI 内输入 `/` 查看全部命令(/resume 恢复会话、/mode 切权限、/profile 切配置、/think 展开思考)。
|
|
91
|
+
|
|
92
|
+
## 已知限制
|
|
93
|
+
|
|
94
|
+
- Windows 写沙箱当前等价于 job 档(真隔离待 ACL,文档如实标注)
|
|
95
|
+
- 黑白名单为防手滑设计(正则可被混淆绕过),对抗性场景用沙箱 / VM
|
|
96
|
+
|
|
97
|
+
## 起源
|
|
98
|
+
|
|
99
|
+
业余项目,开源目的:给想自己搭 coding agent 的开发者一份能跑的参考。名字是 **code + rio**(作者英文名 Lion,本想叫 codelion)。
|
|
100
|
+
|
|
101
|
+
## 贡献与 License
|
|
102
|
+
|
|
103
|
+
欢迎 issue / PR,见 [CONTRIBUTING.md](CONTRIBUTING.md)。MIT License。
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# coderio
|
|
2
|
+
|
|
3
|
+
[中文](README.md) | **English**
|
|
4
|
+
|
|
5
|
+
> The agent claims "done" without running the tests? coderio's harness stops it.
|
|
6
|
+
> A local coding agent with **native Zhipu GLM & StepFun Step coding-plan support** — four-tier permissions, layered sandbox, MCP, lifecycle hooks, and an interactive TUI.
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install coderio
|
|
14
|
+
coderio # onboarding wizard on first launch (pick provider, paste API key, auto context-window probe)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires Python 3.11+; Git Bash on Windows. Linux / macOS supported.
|
|
18
|
+
|
|
19
|
+
## Why coderio
|
|
20
|
+
|
|
21
|
+
The shared weakness of coding agents: **the model says "I'm done" and you just have to trust it**. coderio turns that sentence into a structural constraint—
|
|
22
|
+
|
|
23
|
+
### The Four Gates: the agent can't lie to you
|
|
24
|
+
|
|
25
|
+
| Gate | Behavior |
|
|
26
|
+
|---|---|
|
|
27
|
+
| **VerifyGate** | Wrote code, never ran it, wants to finish → intercepted, forced to continue. Parses real exit codes — **a failing test run does NOT count as verified** |
|
|
28
|
+
| **CompletionGate** | Declares done with pending todos → intercepted |
|
|
29
|
+
| **GroundingGate** | Cites files it never read → intercepted |
|
|
30
|
+
| **PlanGate** | Writes code without a todo list → soft nudge |
|
|
31
|
+
|
|
32
|
+
Not a prompt-level soft rule — a system-level control based on tool-call ground truth. Claude Code and Codex don't have this.
|
|
33
|
+
|
|
34
|
+
### Native Chinese coding-plan support
|
|
35
|
+
|
|
36
|
+
Zhipu **GLM Coding Plan** and StepFun **Step Plan** work out of the box (direct Anthropic-protocol connection) — your subscription quota runs a local agent, no proxies, no middle layer. Also supports OpenAI / Anthropic / Ollama / any OpenAI-compatible endpoint, with multi-profile switching.
|
|
37
|
+
|
|
38
|
+
### Layered security, honestly stated
|
|
39
|
+
|
|
40
|
+
- Four permission tiers (plan read-only / confirm per-action / auto_edit / full)
|
|
41
|
+
- Command blacklist + whitelist (accident prevention); Linux bubblewrap OS sandbox (boundary enforcement)
|
|
42
|
+
- First-use repo-config trust confirmation (hostile-repo protection); web_fetch SSRF protection
|
|
43
|
+
- The blacklist/whitelist are **accident prevention, not adversarial defense** — adversarial protection comes from the sandbox + permissions; use a VM for hostile code
|
|
44
|
+
|
|
45
|
+
## Feature highlights
|
|
46
|
+
|
|
47
|
+
- **Interactive TUI**: streaming output, foldable thinking (Ctrl+O), collapsible TODO panel, vertical permission menu, task interruption (Esc), slash-command autocomplete, session management
|
|
48
|
+
- **Headless mode**: `coderio run "task"` one-shot execution (CI / scripts / benchmarks) with graded exit codes
|
|
49
|
+
- **MCP support**: connect external tools via `.mcp.json` (Claude Code-compatible format), managed with `coderio mcp`
|
|
50
|
+
- **Lifecycle hooks**: `[[hooks]]` run your commands at PreToolUse / PostToolUse / UserPromptSubmit (exit 2 = block) — IO contract compatible with Claude Code
|
|
51
|
+
- **Three-layer skills**: bundled + user + project, progressive disclosure saves context
|
|
52
|
+
- **Context governance**: auto-compaction (60% window trigger), large-block offload, sqlite checkpoints across turns
|
|
53
|
+
- **Subagents**: research (read-only, double-enforced) + general-purpose (inherits the main agent's full security stack)
|
|
54
|
+
- **Engineering discipline**: 850+ tests, 80% coverage, mypy hard gate, uv.lock, 3 OS × 2 Python CI matrix
|
|
55
|
+
|
|
56
|
+
<details>
|
|
57
|
+
<summary><b>Config example</b> (click to expand)</summary>
|
|
58
|
+
|
|
59
|
+
```toml
|
|
60
|
+
# ~/.coderio/config.toml
|
|
61
|
+
[model]
|
|
62
|
+
provider_id = "bigmodel_coding_plan" # Zhipu/StepFun coding plan, or openai/anthropic/ollama/custom
|
|
63
|
+
default = "glm-5.2"
|
|
64
|
+
|
|
65
|
+
[tools]
|
|
66
|
+
permission_mode = "confirm" # plan | confirm | auto_edit | full
|
|
67
|
+
sandbox_mode = "off" # off | job (resource limits) | write (Linux file-write isolation)
|
|
68
|
+
|
|
69
|
+
# Lifecycle hooks (Claude Code-compatible contract)
|
|
70
|
+
[[hooks]]
|
|
71
|
+
event = "PreToolUse"
|
|
72
|
+
matcher = "write_file|edit_file"
|
|
73
|
+
command = "python .hooks/protect.py" # JSON on stdin; exit 2 = block
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
MCP, the sandbox 4-tuple, and more: [docs/coderio-architecture.md](docs/coderio-architecture.md).
|
|
77
|
+
|
|
78
|
+
</details>
|
|
79
|
+
|
|
80
|
+
## Common commands
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
coderio # interactive TUI
|
|
84
|
+
coderio run "fix the failing test" --quiet # headless one-shot
|
|
85
|
+
coderio run "task" --dangerously-skip-permissions # full access (explicit opt-in)
|
|
86
|
+
coderio mcp add github --type http --url ... # manage MCP
|
|
87
|
+
coderio skills install # install skill suites
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Type `/` inside the TUI for all commands (/resume sessions, /mode permissions, /profile configs, /think unfold reasoning).
|
|
91
|
+
|
|
92
|
+
## Known limitations
|
|
93
|
+
|
|
94
|
+
- The Windows write-sandbox currently equals job mode (true isolation awaits the ACL work — documented honestly)
|
|
95
|
+
- Blacklist/whitelist are accident-prevention by design (regex can be bypassed by obfuscation); use the sandbox / a VM for adversarial scenarios
|
|
96
|
+
|
|
97
|
+
## Origin
|
|
98
|
+
|
|
99
|
+
A spare-time project, open-sourced as a working reference for developers building their own coding agents. The name is **code + rio** (the author's English name is Lion; "codelion" sounded odd).
|
|
100
|
+
|
|
101
|
+
## Contributing & License
|
|
102
|
+
|
|
103
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). MIT License.
|
|
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "coderio"
|
|
8
|
-
version = "0.4.
|
|
8
|
+
version = "0.4.3"
|
|
9
9
|
description = "A skill-driven coding agent — structural harness, foldable thinking TUI, deepagents engine."
|
|
10
10
|
readme = "README_en.md"
|
|
11
11
|
license = "MIT"
|
|
@@ -201,10 +201,9 @@ fail_under = 60
|
|
|
201
201
|
# real type errors (wrong arg counts, None where a value is expected) without
|
|
202
202
|
# blocking on the many untyped third-party deps (langchain, deepagents, textual).
|
|
203
203
|
#
|
|
204
|
-
# CI runs mypy as a HARD GATE
|
|
205
|
-
#
|
|
206
|
-
#
|
|
207
|
-
# TODO, not a permanent pass. Remove entries as the files are fixed.
|
|
204
|
+
# CI runs mypy as a HARD GATE for all modules except the override list below.
|
|
205
|
+
# Modules with `ignore_errors = true` have known type issues — each entry is a
|
|
206
|
+
# tracked TODO. Modules are removed from this list when they pass cleanly.
|
|
208
207
|
python_version = "3.11"
|
|
209
208
|
ignore_missing_imports = true
|
|
210
209
|
warn_redundant_casts = true
|
|
@@ -218,6 +217,9 @@ exclude = ["tests/", "build/", "dist/", "\\.venv/"]
|
|
|
218
217
|
# Per-module overrides: lenient modules (tracked cleanup TODOs).
|
|
219
218
|
# Each entry here is a file with known type issues that would block CI if
|
|
220
219
|
# enforced strictly. Remove entries as the files are cleaned up.
|
|
220
|
+
#
|
|
221
|
+
# Cleaned up 2026-08-21: removed coderio.agent.deep_loop and
|
|
222
|
+
# coderio.mcp_loader (verified mypy clean — 0 errors, only notes).
|
|
221
223
|
[[tool.mypy.overrides]]
|
|
222
224
|
module = [
|
|
223
225
|
"coderio.cli.tui",
|
|
@@ -227,10 +229,8 @@ module = [
|
|
|
227
229
|
"coderio.cli.onboarding",
|
|
228
230
|
"coderio.cli.stream",
|
|
229
231
|
"coderio.cli.repl",
|
|
230
|
-
"coderio.agent.deep_loop",
|
|
231
232
|
"coderio.tools.win_job",
|
|
232
233
|
"coderio.tools.win_sandbox",
|
|
233
|
-
"coderio.mcp_loader",
|
|
234
234
|
"coderio.session.store",
|
|
235
235
|
"coderio.session.message",
|
|
236
236
|
"coderio.llm.probe",
|
|
@@ -97,22 +97,48 @@ class _ToolWhitelistMiddleware(AgentMiddleware):
|
|
|
97
97
|
|
|
98
98
|
Wraps the same ModelRequest.override + filter mechanism as
|
|
99
99
|
``_ToolExclusionMiddleware`` but inverts the predicate.
|
|
100
|
+
|
|
101
|
+
Runtime failures degrade to an EMPTY tool set (deny-all), never to the
|
|
102
|
+
unfiltered original — a broken research subagent is preferable to a
|
|
103
|
+
research subagent that can suddenly see write/execute tools (v3 audit #11
|
|
104
|
+
reversed the old fail-open direction).
|
|
100
105
|
"""
|
|
101
106
|
|
|
102
107
|
def __init__(self, *, allowed: frozenset[str]) -> None:
|
|
103
108
|
self._allowed = allowed
|
|
104
109
|
|
|
105
110
|
def wrap_model_call(self, request, handler):
|
|
106
|
-
|
|
111
|
+
try:
|
|
107
112
|
filtered = [t for t in request.tools if _tool_name(t) in self._allowed]
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
return handler(request.override(tools=filtered))
|
|
114
|
+
except Exception as e: # noqa: BLE001 — degrade to deny-all, never fail-open
|
|
115
|
+
_log.warning("tool whitelist failed at runtime (degrading to NO tools): %s", e)
|
|
116
|
+
return handler(request.override(tools=[]))
|
|
110
117
|
|
|
111
118
|
async def awrap_model_call(self, request, handler):
|
|
112
|
-
|
|
119
|
+
try:
|
|
113
120
|
filtered = [t for t in request.tools if _tool_name(t) in self._allowed]
|
|
114
|
-
|
|
115
|
-
|
|
121
|
+
return await handler(request.override(tools=filtered))
|
|
122
|
+
except Exception as e: # noqa: BLE001 — degrade to deny-all, never fail-open
|
|
123
|
+
_log.warning("tool whitelist failed at runtime (degrading to NO tools): %s", e)
|
|
124
|
+
return await handler(request.override(tools=[]))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class _DenyAllToolsMiddleware(AgentMiddleware):
|
|
128
|
+
"""Last-resort middleware: the model sees ZERO tools.
|
|
129
|
+
|
|
130
|
+
Returned when the whitelist middleware itself cannot be constructed — the
|
|
131
|
+
research subagent becomes useless but stays harmless (v3 audit #11: the
|
|
132
|
+
old fallback was an EMPTY middleware list, i.e. the subagent inherited
|
|
133
|
+
EVERY tool including write/execute — fail-open in the most dangerous
|
|
134
|
+
direction).
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
def wrap_model_call(self, request, handler):
|
|
138
|
+
return handler(request.override(tools=[]))
|
|
139
|
+
|
|
140
|
+
async def awrap_model_call(self, request, handler):
|
|
141
|
+
return await handler(request.override(tools=[]))
|
|
116
142
|
|
|
117
143
|
|
|
118
144
|
def make_research_subagent_middleware():
|
|
@@ -126,8 +152,8 @@ def make_research_subagent_middleware():
|
|
|
126
152
|
|
|
127
153
|
Returns a list with a _ToolWhitelistMiddleware. If the deepagents
|
|
128
154
|
AgentMiddleware base class API is unavailable (very old or very new
|
|
129
|
-
version),
|
|
130
|
-
(
|
|
155
|
+
version), falls back to _DenyAllToolsMiddleware — the subagent sees no
|
|
156
|
+
tools rather than all of them (fail-closed; v3 audit #11).
|
|
131
157
|
"""
|
|
132
158
|
# Read-only tools the research subagent is allowed to use. Add new tools
|
|
133
159
|
# here ONLY after confirming they're safe for a read-only agent.
|
|
@@ -135,5 +161,8 @@ def make_research_subagent_middleware():
|
|
|
135
161
|
try:
|
|
136
162
|
return [_ToolWhitelistMiddleware(allowed=allowed)]
|
|
137
163
|
except Exception as e: # noqa: BLE001 — AgentMiddleware API may differ
|
|
138
|
-
_log.warning("Could not build _ToolWhitelistMiddleware: %s", e)
|
|
139
|
-
|
|
164
|
+
_log.warning("Could not build _ToolWhitelistMiddleware (deny-all fallback): %s", e)
|
|
165
|
+
try:
|
|
166
|
+
return [_DenyAllToolsMiddleware()]
|
|
167
|
+
except Exception: # noqa: BLE001 — even the fallback construction failed
|
|
168
|
+
return []
|