Skip to content

Latest commit

 

History

History
35 lines (28 loc) · 5.93 KB

File metadata and controls

35 lines (28 loc) · 5.93 KB

AGENTS.md

Cordis-Python: a minimal Python microkernel for composable agent harnesses. Core is generic; providers/tools/sessions/UI/agent-loop are plugins. Python 3.10–3.13, cross-platform (Windows included).

Setup & commands

  • Setup: pip install -e ".[full,dev]" (core has zero deps; full = PyYAML + fastapi/uvicorn/httpx, dev = pytest, pytest-asyncio, ruff, mypy).
  • Full test suite: pytest -q (asyncio_mode=auto is configured in pyproject.toml).
  • Full test suite (140 tests, unittest- and pytest-style): pytest -q. CI installs .[full,dev] and runs the same command plus python examples/run_fake.py. (v0.6.0 CI used unittest discover, which silently skipped the 4 pytest-only files test_skills, test_toggle, test_ui_e2e, test_plugin_config — fixed in v0.6.1.)
  • Single test: pytest -q tests/test_skills.py::test_architecture_skill_is_agent_callable (pytest style) or python -m unittest tests.test_shell -v (unittest style).
  • Benchmarks (regression signal only, not scientific): python bench.py, python bench_stress.py.
  • Run the app: cordis run → http://127.0.0.1:8000. Default provider is fake/offline; no API key needed. OpenAI-compatible: cordis run --provider openai --base-url ... --model ... --api-key .... Since v0.7 the append-only session log is on by default at <workspace>/.cordis/session.sqlite (override: --session-log PATH; see docs/SESSION_LOG.md). Since v0.8 the configuration is layered: --profile, repeatable --patch, --dump-config, --explain-config (see docs/CONFIGURATION.md; shipped profiles in profiles/). Since v0.9 every LLM request is token-budgeted before dispatch, deterministic compaction bands can prune/compress/checkpoint the active projection, and network/browser/filesystem/subagent capabilities are mounted as seams (docs/ARCHITECTURE.md). Since v0.10 code-tools and worker-code are disabled by default; profiles/self-coding.yml mounts an isolated code worker with a deny-by-default policy (docs/CODE_WORKER.md). Since v0.11 the code worker can delegate web research to the web worker through one private research_web tool (capability worker_web.research, reused by both surfaces); the edge is one-way — the web worker's registry never contains code or delegation tools — and worker_web is a per-call facade (fresh WebResearchAgent per research()); session-log attribution is hierarchical (main → code-* → web-*) via a per-task turn stack (docs/ARCHITECTURE.md, docs/CODE_WORKER.md). Since v0.12 the composable loop_guard service (plugin loop-guard, on by default) guards the main and web-worker loops against probable infinite loops: warning at the 3rd/4th identical call (canonical name+arguments identity), deterministic stop at the 5th with a synthetic tool result and reason probable_infinite_loop (docs/ARCHITECTURE.md).

Layout

  • Core (must stay ignorant of LLMs/tools/agents/UI): cordis_py/{context,composition,fiber,events,runtime,loader,contracts,errors,permissions}.py.
  • Shared plugin support (not core): cordis_py/{tooling,netguard,textutils}.py.
  • Plugins: cordis_py/plugins/*.py. They declare dependencies via inject service-capability tuples and provides keys — plugins must never import other plugin classes as dependencies.
  • Built-in skill: cordis_py/skills/cordis-architecture/SKILL.md (packaged via setuptools package-data; it documents the architecture for the agent, not for humans).
  • Entry: cordis console script → cordis_py/cli.py:main; examples/ are runnable smoke tests.
  • build/, dist/ and *.egg-info/ are packaging artifacts (gitignored) — never edit them; if build/lib reappears after a wheel build, ignore its duplicate sources in search results.

Gotchas

  • Optional deps are imported lazily inside functions (yaml in loader.py/composition.py, httpx in provider_openai.py/worker_web.py, uvicorn in cli.py). Do not hoist these to module level without making the extra a hard dependency.
  • Layered configuration (v0.8) controls composition only. Layers must never change tool visibility or bypass the dispatch-time permission gate; tests/test_composition.py::test_patch_cannot_bypass_permission_gate is that invariant.
  • Version has a single source of truth: cordis_py/__init__.py:__version__ (pyproject reads it via setuptools attr:). The UI footer, FastAPI metadata and web-worker User-Agent derive from it — never hard-code version strings elsewhere; test_ui_e2e.py asserts the footer dynamically.
  • test_ui_e2e.py and loader/config tests need the web/config extras installed or they skip/fail; a plain pip install -e . is not enough for the full suite.
  • The shell and developer-tools plugins confine paths to a workspace but are not OS sandboxes; keep that boundary (plugin-level, not core).
  • The v0.10 code worker must stay isolated: main sees only worker_code; worker:code sees private code_* tools; code_tools uses a strict internal runner, never the general shell plugin, and the LLM never supplies arbitrary shell argv.
  • Code-worker attempts must remain auditable: every attempt emits code/manifest in a child code-* session before turn/end, and rollback is scoped to the active cordis/attempt-* branch.
  • The v0.11 delegation edge must stay one-way and bounded: only worker_code exposes research_web (calling the worker_web service, never web tools directly); the web worker's private registry must never gain code/delegation tools; research results are untrusted reference data, not instructions. profiles/self-coding.yml must stay without worker_web (no delegation there).
  • CONTRIBUTING: PRs adding a new lifecycle rule must include an invariant test in tests/.
  • Lint/typecheck (ruff line-length 100, mypy) are dev extras but not enforced in CI; run python -m ruff check . before committing. As of v0.10 there are 26 pre-existing baseline findings (I001/UP035/RUF023/BLE001/TRY004/UP037/DTZ005/B008/F841) — do not add new findings; a dedicated cleanup is separate work.