* Add five community security skills for agent specialization
Expand coverage with OAuth flow testing, AWS misconfigurations, prototype
pollution, insecure deserialization, and Django framework playbooks.
* Address Greptile review feedback on AWS and deserialization skills
- Use head-bucket for S3 existence checks instead of duplicating s3 ls
- Add Node.js to insecure_deserialization frontmatter description
* Clarify S3 existence vs public listing checks in aws skill
Split unauthenticated enumeration into separate head-bucket/HTTP
and s3 ls steps with interpretation guidance per review.
* some tools ads
---------
Co-authored-by: bearsyankees <bearsyankees@gmail.com>
Brings in 10 commits from main on top of the v1.0.0 branch.
Resolutions:
- Legacy harness files modified on main but deleted in the migration —
kept as deleted: strix/agents/base_agent.py, strix/agents/state.py,
strix/config/config.py, strix/llm/llm.py,
strix/llm/memory_compressor.py, strix/llm/utils.py,
strix/runtime/docker_runtime.py.
- tests/runtime/test_docker_runtime.py — removed; tests dead code.
- strix/skills/vulnerabilities/idor.md and ssrf.md — auto-merged.
- New skills from main kept: header_injection.md, http_request_smuggling.md,
nosql_injection.md, ssti.md.
Five rounds of sweep across the tree. Net ~544 lines removed.
Removed:
- Section-divider banners and one-line section labels (# Display
utilities, # ----- list_requests -----, # CVSS breakdown, etc.).
- Module-level prose docstrings on internal modules. Kept one-line
summaries; trimmed multi-paragraph narration about SDK/Strix
responsibility splits, cache strategies, three-source precedence.
- Internal-helper docstrings that just restate the function name —
caido_api helpers (caido_url, get_client, view_request, etc.),
settings-class one-liners (LLMSettings, RuntimeSettings, ...),
UI helper docstrings.
- Args/Returns blocks on non-LLM-facing internal helpers
(build_strix_agent, render_system_prompt, create_or_reuse,
bootstrap_caido) — kept only the genuinely non-obvious params.
- Internal-history phrasing — "Mirrors main-branch shape",
"pre-SDK harness", "previous lookup matched no attribute".
- Narrative comments inside function bodies that explained what the
next line does, design rationale obvious from the surrounding code,
or "we used to..." asides.
- Trailing periods on every error-string literal across the tool tree.
- Duplicated roundtripTime quirk comment (kept the LLM-facing copy in
tools/proxy/tools.py).
Kept (every one names an upstream bug, vendored-code provenance, or
non-obvious data quirk):
- core/runner.py: SDK replay-with-empty-initial-input + on_agent_end
lifecycle gap.
- runtime/docker_client.py: VERBATIM COPY block of the upstream
_create_container body, pinned to SDK v0.14.6.
- runtime/session_manager.py: NO_PROXY for agent-browser CDP loopback.
- tools/proxy/caido_api.py: generated-pydantic Request.raw quirk,
replay double-history pitfall.
- tools/proxy/tools.py: Caido roundtripTime=0 quirk for proxy
captures.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The image ships 15 tools (jwt_tool, interactsh-client, arjun, dirsearch,
gospider, wafw00f, retire, eslint, jshint, js-beautify, JS-Snooper,
jsniper.sh, vulnx, ncat, uv) that the always-loaded skills never name
with usage guidance — agents could discover them via the environment
catalog but had no when/how. Add concise mentions in the natural home
for each: jwt_tool in the JWT skill, interactsh-client in the OAST
sections of SSRF/XXE/RCE, arjun in IDOR recon, dirsearch as the broad
alternate in the ffuf skill, gospider + the JS scrapers in katana,
wafw00f next to httpx, retire/eslint/jshint/js-beautify as a new
JavaScript-Side Coverage block in the SAST playbook, uv in python,
vulnx in the deep scan-mode CVE bullet, ncat in a new RCE Tooling
block.
Audit also turned up three real breakages along the way:
- jwt_tool's shebang resolves to /usr/bin/python3 but its dependencies
live in /app/.venv, so every invocation died with
ModuleNotFoundError: ratelimit. Replace the bare symlink with a
wrapper that execs /app/.venv/bin/python against the real script.
- dirsearch's pipx venv ended up with setuptools 82, which dropped
pkg_resources — startup failed before parsing args. Pin the inject
to setuptools<81.
- ESLint's --no-eslintrc flag was removed in v9; the surviving
--no-config-lookup covers it. Drop the dead flag from the SAST
command block.
Also corrected the JS-Snooper / jsniper.sh entry in katana.md — both
take a bare domain and run their own JS discovery internally, not the
JS URLs Katana already harvested.
AGENT_BROWSER_ARGS parser splits on commas, so any flag value
containing one (--disable-features=A,B, --window-size=1920,1080,
--lang=en-US,en) shredded into garbage positionals and Chromium
rejected the launch with "Multiple targets are not supported in
headless mode". Reduce to a comma-separated list of comma-free
flags that keeps the AutomationControlled anti-detection bit.
Default screenshot path now resolves inside the workspace root so
view_image accepts it; entrypoint pre-creates the dir at runtime
(the build-time mkdir is shadowed by the /workspace mount). Skill
examples updated to favor the no-arg form, plus brief fallback
guidance when view_image is unavailable on text-only models and a
viewport-resize note for sites that gate on real desktop dims.
Also drop the stale STRIX_DISABLE_BROWSER doc entry — no code
reference exists.
Main's load_skill tool was deleted during the SDK migration along
with the prompt-mutation pattern it relied on. Re-add the capability
without the mutation: load_skill(skills=[...]) now returns the skill
markdown bodies as a tool result, so the content lands in conversation
history as in-context reference rather than as patched-in system
prompt content. Same source of truth (load_skills + skill files),
same validation (validate_requested_skills) as create_agent.
Tool result format is plain markdown (## Skill: <name> headers joined
with ---), not the <specialized_knowledge> XML wrapping used at
agent-build time. The XML framing was deliberately reserved for
prompt-level privileged context; tool-loaded skills are honestly
labelled as just-fetched reference material.
Close the discovery loop by surfacing the full skill catalog in the
system prompt. Without it the model could only guess skill names —
discovering them via validation errors on misses. Now every agent
sees a categorised <available_skills> block right after the
<specialized_knowledge> block with a short hint pointing at
create_agent / load_skill.
Skills module: factored _iter_user_skill_files() so get_all_skill_names
(set, for validation) and get_available_skills (dict by category,
for the prompt) share one source of truth on what counts as
user-selectable. Internal categories (scan_modes, coordination) stay
excluded from both.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three concrete wraps on exec_command / write_stdin via the existing
Shell capability configure_tools mechanism, plus one skill-doc fix.
All wraps fire on both Responses and chat-completions paths; the
chat-completions error-as-result wrap still stacks on top when needed.
- write_stdin: decode the common escape forms in `chars` (\uXXXX,
\xXX, \n \t \r \0 \a \b \v \f \\). Models routinely send the
literal six-char string `` intending the ASCII control byte;
the SDK takes chars verbatim so the byte never reaches the PTY and
documented mechanisms like Ctrl-C, arrows, and Escape silently
don't work. Allowlist regex over recognized escapes only —
unrecognized sequences like `\p` pass through untouched.
- exec_command: catch InvalidManifestPathError and rewrite to a
model-actionable message ("workdir must be a path inside
/workspace") using the exception's structured `context["rel"]` so
we don't need to string-match the SDK's wording.
- Both tools: catch pydantic ValidationError once at the wrap and
reformat into a short "{tool}: invalid arguments — {field}: {msg}"
string. Covers empty cmd, missing required fields, ge/min_length
violations on max_output_tokens and yield_time_ms — and any future
schema field the SDK adds.
Updated python.md guidance: the `shell=` parameter is for swapping
POSIX shells (bash/zsh/sh). Interpreters belong in `cmd` —
`cmd="python3 -c '...'"`, not `shell=python3`. The `shell=interpreter`
shortcut breaks in interpreter-specific ways (python needs `-c`,
node/ruby/perl need `-e`) so there's no clean code fix and we don't
try one.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- view_agent_graph status summary now derives buckets from the canonical
Status literal via get_args, so adding a new status in core.agents
auto-flows into the summary. The previous hardcoded five-bucket list
silently omitted "failed" — buckets stopped summing to total whenever
an agent failed.
- stop_agent rejects targets that are already in a terminal status
(completed / stopped / crashed / failed) with a model-readable error
pointing at view_agent_graph and send_message_to_agent. request_stop
unconditionally overwrites status, so without this guard calling
stop_agent on a completed agent erased the "completed" history.
- StopAgentRenderer added — was falling back to the generic key/value
renderer; the rest of the agents_graph tools have purpose-built ones.
- agent_finish root-rejection payload trimmed from
{success, agent_completed, error, parent_notified} to {success, error}.
The lifecycle gate only reads success+agent_completed and they were
always False/False on this branch, so the extra fields were dead weight.
- wait_for_message renames its top-level outcome field from "status" to
"wait_outcome" — "status" overloaded with the coordinator's agent
status literal (which also has "stopped" as a value, different
meaning). Redundant "agent_waiting" boolean dropped (true iff
wait_outcome == "waiting"). Consumer at factory._wait_tool_parked
updated to match.
- send_message_to_agent now refuses self-send with a pointer at think /
agent_finish / finish_scan instead of looping a message into your
own session.
- SendMessageToAgentRenderer read args.get("agent_id") but the tool's
param is target_agent_id, so the TUI silently never showed the target.
Fixed.
- Restored skill validation lost during the SDK migration: skills
module re-exports get_all_skill_names and validate_requested_skills
(excluding internal scan_modes/coordination categories from the
user-selectable set). create_agent now validates skills before
spawning instead of silently accepting unknown names.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-add list_sitemap and view_sitemap_entry from main, ported to the
new caido-sdk-client layout via raw GraphQL queries (the typed SDK
doesn't expose sitemap operations, but the Caido server still
supports sitemapRootEntries / sitemapDescendantEntries / sitemapEntry).
Wired through caido_api (sandbox-importable helpers), the host-side
@function_tool wrappers, factory _BASE_TOOLS, the system prompt, the
python skill doc, and the public proxy docs.
While threading these through, lock down the output contract across
every proxy tool so the model sees one consistent shape:
- All tools wrap success/failure in {"success": bool, "error"?: str}
- Canonical field names: status_code, length, roundtrip_ms (omitted
when 0), is_tls, has_descendants. snake_case everywhere on output;
camelCase stays only on the input side where it's the GraphQL
schema.
- repeat_request now returns a structured response that matches
list_requests' response_summary shape (parse_raw_response parses
the raw bytes into status_code / length / headers / body), with
body capped at 8KB and a body_truncated flag so the model knows
when to fetch the full body via view_request.
- RepeatRequestRenderer was reading non-existent top-level keys
(status_code, response_time_ms, body) and silently displaying
nothing useful — now reads the structured response shape.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
send_request was a thin wrapper over the Caido Replay API that the model
could replicate with a one-liner `curl` via exec_command. The sandbox's
HTTP_PROXY env captures all such traffic for free, so the tool was
adding bugs (duplicate dispatch, dropped responses) without adding
capability. Removed across factory, tools module, sandbox-importable
caido_api helper, TUI renderer, prompt template, skill doc, and public
docs. repeat_request stays — it operates on captured request IDs with
structured modifications, which curl can't replicate cleanly.
Three caido-sdk-client workarounds that were hitting us through both
send_request and repeat_request:
- replay_send_raw used to pass CreateReplaySessionFromRaw to
sessions.create(), which seeds a stored entry server-side, then
called send() — producing two history rows per call. Empty-create +
send produces one dispatched request.
- The same helper read result.entry.response_raw, an attribute that
doesn't exist on ReplayEntry, so response bytes were silently
dropped. Fixed to walk result.entry.response.raw with proper None
guards.
- get_request_with_client passed include_request_raw / include_response_raw
based on the requested part, but the SDK's generated pydantic models
declare raw as required even though the GraphQL fragment makes it
conditional via @include. Passing False crashed view_request with a
pydantic validation error. Always request both raw bodies; the caller
picks which to surface.
Also wrapped replay.send() in asyncio.wait_for(30s) so a stalled Caido
dispatch (notably loopback targets that don't route cleanly through the
sandbox proxy) fails fast with a model-readable error instead of
hanging the agent until the function_tool 120s budget expires.
Finally, list_requests now omits the roundtrip_ms field when Caido
reports 0 — proxy-captured unscoped traffic consistently reports 0
while scoped/replay traffic carries real measurements, so the absence
of the field is now informative ("Caido didn't measure this") rather
than misleading ("this request took 0ms").
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add HTTP request smuggling skill
Add a new vulnerability skill covering HTTP request smuggling (HRS)
across CL.TE, TE.CL, H2.CL, and H2.TE desync variants. HRS is absent
from the existing skill set despite being a distinct, high-impact
vulnerability class frequently present in any architecture using a
reverse proxy or CDN in front of an application server.
Coverage:
- CL.TE: front-end uses Content-Length, back-end uses Transfer-Encoding
- TE.CL: front-end uses Transfer-Encoding, back-end uses Content-Length
- H2.CL: HTTP/2 front-end downgrades to HTTP/1.1 with injected Content-Length
- H2.TE: Transfer-Encoding header injection through HTTP/2 desync
- Transfer-Encoding obfuscation techniques (tab, space, duplicate, xchunked)
- Front-end security control bypass via smuggled prefix
- Cross-user request capture for session token theft
- Response queue poisoning and WebSocket handshake hijacking
- Timing-based and differential response detection methodology
- HTTP/2 specific probing techniques
Includes raw HTTP examples for each variant, step-by-step testing
methodology, exploitation PoCs, false-positive conditions, and
infrastructure topology guidance.
* fix: correct TE.CL probe, pseudo-header terminology, PoC Content-Length values, \x20 representation
Four reviewer findings addressed:
P1 — TE.CL timing-probe description inverted: previous text said
'Content-Length set to fewer bytes than the chunk content' which
describes socket-poisoning behavior (differential response), not a
timeout. Corrected to: send a complete chunked body with CL set to MORE
bytes than provided so the back-end waits for data that never arrives.
Also corrected Testing Methodology step 3 to match.
P2 — pseudo-header terminology: 'content-length' is a regular HTTP/2
header, not a pseudo-header (pseudo-headers are exclusively :method,
:path, :authority, :scheme). Fixed the H2.CL explanation (line 75),
HTTP/2-specific detection bullet, and Pro Tip #4 which referred to
':content-length pseudo-header'.
P2 — PoC Content-Length values: outer Content-Length in the bypass PoC
corrected from 116 to 100 (actual byte count of the body shown); capture
PoC corrected from 129 to 120.
P2 — \x20 representation: replaced the \x20 escape sequence in the code
block (which renders as a literal four-character string, not a space byte)
with an explanatory comment and actual whitespace characters so the intent
is unambiguous.
* Update strix/skills/vulnerabilities/http_request_smuggling.md
The notes tool no longer touches disk. ``_notes_storage`` lives in
memory for the lifetime of one scan process, shared across every
agent in that process via the existing RLock. Process exit clears
the lot — no notes.jsonl event log, no wiki/<slug>.md Markdown
rendering, no replay-on-startup hydration.
Removed ~10 internal helpers (``_get_run_dir``,
``_get_notes_jsonl_path``, ``_append_note_event``,
``_load_notes_from_jsonl``, ``_ensure_notes_loaded``,
``_persist_wiki_note``, ``_remove_wiki_note``,
``_get_wiki_directory``, ``_get_wiki_note_path``,
``_sanitize_wiki_title``) plus the ``_loaded_notes_run_dir`` module
state, ``wiki_filename`` per-note field, and the ``OSError`` branches
that only existed for the wiki write path.
The ``wiki`` category is preserved as a free-form long-form bucket;
it just no longer has any special persistence behaviour.
Skill prompts scrubbed of every "shared wiki memory" / "repo wiki" /
"append a delta before agent_finish" instruction:
``coordination/source_aware_whitebox.md``,
``custom/source_aware_sast.md``,
``scan_modes/{quick,standard,deep}.md``, plus the WHITE-BOX TESTING
block in ``agents/prompts/system_prompt.jinja``.
HARNESS_WIKI.md updated to drop the wiki-as-shared-knowledge-base
description, the per-run output-tree references to ``notes/notes.jsonl``
and ``wiki/{note_id}-{slug}.md``, and the ``is_whitebox`` toggle prose.
Net: -178 LoC in notes/tools.py, -45 LoC across skills/system_prompt
and the wiki doc. The notes tool surface (5 ``@function_tool``s) is
unchanged for the agent.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every scan now writes a complete log file at ``{run_dir}/strix.log``
captured from the moment ``run_dir`` is resolved through teardown.
Stdlib ``logging`` only — no parallel framework.
New ``strix/telemetry/logging.py``:
* ``setup_scan_logging(run_dir, debug=)`` attaches a ``FileHandler``
(DEBUG, all ``strix.*``) plus a ``StreamHandler`` (ERROR by
default; DEBUG via ``STRIX_DEBUG=1``).
* ``ContextVar``-backed ``scan_id`` and ``agent_id`` injected by a
``Filter`` so every line is auto-tagged across asyncio tasks
without callers passing them explicitly.
* Third-party noise (``httpx``, ``litellm``, ``openai``,
``anthropic``, ``urllib3``, ``httpcore``) capped at WARNING.
* Returns a teardown handle for ``finally`` cleanup.
Wiring:
* ``orchestration/scan.py`` calls ``setup_scan_logging`` once per
scan after ``run_dir`` resolves; sets scan_id; tears down in
``finally``. Adds INFO logs for sandbox bring-up + scan
start/end.
* ``orchestration/hooks.py`` sets/clears ``agent_id`` ContextVar in
``on_agent_start`` / ``on_agent_end`` and emits INFO for agent
lifecycle, DEBUG for every tool start/end and LLM call.
* ``interface/main.py`` drops the ``setLevel(ERROR)`` silencer.
Coverage expanded across ~20 files (orchestration, agents, runtime,
llm, tools, interface, config, skills) with INFO for lifecycle and
DEBUG for verbose detail. Per the system instructions in
``logger.warning(f"…{e}")`` were converted to module logger calls.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restores the legacy persistent-IPython tool's *ergonomics* (proxy
helpers pre-bound, structured stdout/stderr/error returns) without the
in-container daemon: each call ships ``strix.tools.proxy._calls`` source
into ``/tmp`` alongside a per-call driver, runs ``python3 -u`` against
it, and parses a sentinel-delimited JSON payload back from stdout. The
driver fetches its own guest token from Caido at ``localhost:48080``
and binds ``list_requests`` / ``view_request`` / ``send_request`` /
``repeat_request`` / ``scope_rules`` to that client; user code runs
inside an ``async def`` wrapper so top-level ``await`` works.
The proxy SDK call sequences live in one file —
``strix/tools/proxy/_calls.py`` — and are reused by both the host-side
``@function_tool`` wrappers (which add JSON serialization for the LLM)
and the in-container kernel (which exposes the bare async functions).
No code duplication; the helper logic itself is host-shipped, so
tweaking the proxy helpers does not require an image rebuild.
Image: a single ``pip install caido-sdk-client`` line so the driver's
``import caido_sdk_client`` resolves. Skill ``tooling/python`` is
always-loaded alongside ``tooling/agent_browser``.
Trade-off accepted: state does not persist across calls (no kernel).
For multi-step workflows the agent combines into one ``code`` block or
writes a script to ``/workspace/scratch/`` and runs via
``exec_command``. If a workflow surfaces that genuinely needs
persistence, the same tool surface migrates to a kernel-backed
executor without changing the LLM contract.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The vendored agent-browser skill described the ``screenshot``
subcommand but didn't tell the model how to actually look at the
resulting PNG. ``agent-browser screenshot`` writes to disk; the
SDK's ``view_image`` (from the ``Filesystem`` capability we already
enable on the agent) is what loads the bytes back as multimodal
content.
Add the explicit two-step pattern:
exec_command: agent-browser screenshot /workspace/page.png
view_image: {"path": "/workspace/page.png"}
Plus a guidance note that ``snapshot -i`` (text accessibility tree at
~200-400 tokens) is the cheap default and screenshots are for cases
where pixels actually matter — visual layout, captchas, custom
widgets where the a11y tree is incomplete.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Combined commits 2+3 of the migration plan because the FastAPI sidecar
removal in commit 2 broke ``browser_action`` (which lived in the
sidecar); they have to land together.
Sandbox tool layer (commit 2 piece):
- ``build_strix_agent`` now returns a ``SandboxAgent`` with
``capabilities=[Filesystem(), Shell()]``. The SDK runtime binds the
capabilities to the live sandbox session per-run; agents get
``exec_command``, ``write_stdin``, ``apply_patch``, ``view_image``
function tools auto-merged into their tool list. Plain ``Agent``
short-circuits capability binding (``agents/sandbox/runtime.py:190``).
- Drop ``Compaction`` from the default capability set — it's
OpenAI-Responses-API-only and useless for our litellm-routed
Anthropic setup.
- Delete the entire custom in-container tool layer:
- ``strix/tools/terminal/`` (5 files, 748 LoC libtmux)
- ``strix/tools/file_edit/`` (3 files, 276 LoC)
- ``strix/tools/python/`` (5 files, 459 LoC)
- ``strix/runtime/tool_server.py`` (163 LoC FastAPI sidecar)
- ``strix/tools/_sandbox_dispatch.py`` (117 LoC)
- ``strix/tools/registry.py`` (109 LoC)
- ``strix/tools/context.py`` (12 LoC)
- Drop the corresponding TUI renderers (``terminal_renderer.py``,
``file_edit_renderer.py``, ``python_renderer.py``) and update
``interface/tool_components/__init__.py``.
Browser → agent-browser CLI (commit 3 piece):
- Install ``agent-browser@0.26.0`` globally in the Dockerfile right
after the existing ``npm install -g`` block. Run
``agent-browser install --with-deps`` (apt, root) and
``agent-browser install`` (Chrome download, pentester) +
``agent-browser doctor --offline --quick`` smoke test.
- Drop the explicit Playwright system-deps apt list (replaced by
``--with-deps``) and ``RUN .venv/bin/python -m playwright install
chromium``.
- Vendor ``agent-browser/skill-data/core/SKILL.md`` →
``strix/skills/tooling/agent_browser.md`` (476 lines). Adapt
frontmatter to Strix format; strip the install/Quickstart and the
``agent-browser skills get electron|slack|...`` specialized-skills
block; add the "Caido proxy is wired via env vars; do not pass
``--proxy``" note.
- ``_resolve_skills`` now eagerly loads ``tooling/agent_browser`` for
every agent (matches the previous unconditional ``browser_action``
in ``_BASE_TOOLS``).
- Delete ``strix/tools/browser/`` (5 files, 1338 LoC) and the
``browser_renderer.py`` TUI render.
Sandbox plumbing:
- Drop ``bearer`` token, ``tool_server_host_port`` resolution + bundle
keys, ``TOOL_SERVER_TOKEN``/``TOOL_SERVER_PORT``/
``STRIX_SANDBOX_EXECUTION_TIMEOUT`` from the manifest env in
``session_manager.create_or_reuse``. Caido proxy env vars
(``http_proxy``, ``https_proxy``, ``ALL_PROXY``) stay; manifest
applies them to every ``docker exec``-spawned process.
- Drop ``sandbox_token`` and ``tool_server_host_port`` params from
``make_agent_context`` and the ``create_agent`` graph tool.
- Drop the tool-server health-check from ``entry.py`` (only Caido's
``wait_for_tcp_ready`` remains).
- ``docker-entrypoint.sh``: delete the ~30 line
``Starting tool server...`` block (sudo + uvicorn launch + curl
/health poll). Add ``NO_PROXY=localhost,127.0.0.1`` to
``/etc/profile.d/proxy.sh`` and ``/etc/environment`` so the
agent-browser daemon's CDP traffic on localhost isn't routed
through Caido.
pyproject.toml:
- ``[project.optional-dependencies] sandbox = []`` (every member of
the previous list — fastapi, uvicorn, ipython, openhands-aci,
playwright, libtmux — is gone with the sidecar).
- Drop ``numpydoc.*``, ``IPython.*``, ``openhands_aci.*``,
``playwright.*``, ``uvicorn.*``, ``pyte.*``, ``libtmux.*`` from
the missing-imports module list.
- Drop the per-file ruff ignores for the deleted modules.
Net delta: −5512 LoC. ruff drops to 3 errors (was 21 baseline). mypy
falls to 69 errors over 3 files (was 84 over 8 — the drop comes from
deleting the modules with the worst untyped-import problems).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Specify encoding="utf-8" in registry.py _load_xml_schema()
- Specify encoding="utf-8" in skills/__init__.py load_skills()
- Prevents cp949/shift_jis/cp1252 decoding errors on non-English Windows