Makes your AI agent think like the laziest senior dev in the room. The best code is the code you never wrote.
Copilot CLI plugin for sandboxed CodeAct runs
CodeAct packages a Copilot CLI plugin that collapses multi-step tool chains into one sandboxed Python execution. The plugin registers built-in-style tools such as `view`, `edit`, `glob`, `bash`, `sql`, `grep`, `web_fetch`, and `github_api`, and it can be configured with allowlists, denylists, and custom tools. The repo also includes installation instructions, backend switching between `monty` and `hyperlight`, and end-to-end tests that compare baseline Copilot CLI runs against CodeAct runs.
Builders who use Copilot CLI and want their agent to work through code tasks with fewer turns and less repeated context.
You can turn a long chain of tool calls into one scripted pass, which cuts repeated context and makes runs cheaper and shorter.
What it does
Single-turn tool chaining
Lets the agent write one Python program that calls multiple tools in sequence instead of bouncing between model and tool repeatedly.
Sandboxed execution
Runs the Python program in a sandbox, with `monty` or `hyperlight` as the execution backend.
Copilot-style tool catalog
Registers tools named `view`, `create`, `edit`, `glob`, `bash`, `sql`, `grep`, `web_fetch`, and `github_api`.
Tool allowlist and denylist
Supports `CODEACT_DISABLE` and `CODEACT_TOOLS`, plus persisted config in `~/.config/codeact/config.json`.
Custom tool loading
Loads extra tools from `~/.config/codeact/tools/`, where each `.py` file becomes a tool after re-running `/codeact-install`.
Backend switching
Supports `/codeact-install-monty` and `/codeact-install-hyperlight`, or `--backend monty|hyperlight` during install.
Performance test harness
Provides unit, functional, and perf runs through `uv run plugins/codeact/tests/run_tests.py ...`, plus result comparison with `compare_results.py`.
How to get it
- 1From local checkout (development)
copilot plugin install ./plugins/codeact bash plugins/codeact/scripts/install-instructions.sh
README
CodeAct — Copilot CLI Plugin
Collapse multi-step tool chains into a single sandboxed Python execution. Instead of N individual tool calls (model → tool → model → tool …), the agent writes one Python program that chains all the tools together and runs it in a single turn.
Why CodeAct?
Instead of N individual tool calls (model → tool → model → tool …), the agent writes one Python program that chains all the tools together and runs it in a single turn. Fewer turns means the conversation context — system prompt, tool definitions, prior messages — is replayed fewer times. With MCP servers loaded, each server's tool catalog adds to that context, so the savings compound.
Each test runs the same prompt twice: once as a baseline (standard Copilot CLI, no plugin) and once with codeact (plugin loaded). Token counts are extracted from copilot process logs. Tests use a 30+ file Python project with handlers, services, middleware, configs, and tests.
| Task | Turns | Input Tokens | Est. Cost Savings |
|---|---|---|---|
| Test coverage + 4 MCP servers | 6 → 2 | 335K → 103K | 69% |
| Full project function index | 4 → 2 | 130K → 57K | 57% |
| Test coverage (no MCP) | 4 → 2 | 123K → 58K | 57% |
| Docstring coverage | 3 → 2 | 86K → 56K | 49% |
| MCP docs cross-ref + 4 servers | 3 → 3 | 167K → 88K | 49% |
Cost estimated at GPT-5.4 pricing ($2.50/M input, $15/M output). Run uv run plugins/codeact/tests/run_tests.py perf --backend monty to reproduce.
For more on the pattern, see CodeAct with Hyperlight from Microsoft.
Before / After
Before (standard): 8 tool calls, 12 API requests, ~1,250 output tokens
model: "I'll search for TODOs" → grep → model: "Found matches in 3 files"
→ view file1 → model: "File 1 has..." → view file2 → model: "File 2 has..."
→ view file3 → model: "File 3 has..." → model: "Here's the summary..."
After (codeact): 1 tool call, 4 API requests, ~450 output tokens
model: "I'll find all TODOs in one pass" → bash codeact.py --code '
for f in glob(pattern="**/*.py"):
content = view(path=f)
for i, line in enumerate(content.split(chr(10))):
if "TODO" in line:
print(f"{f}:{i+1}: {line.strip()}")
' → model: "Here are all TODOs..."
Install
From marketplace (recommended):
copilot plugin marketplace add jsturtevant/copilot-skills
copilot plugin install codeact@copilot-skills
# First time use — run inside Copilot CLI
/codeact-install
# Or run install script directly
bash ~/.copilot/installed-plugins/copilot-skills/codeact/scripts/install-instructions.sh
# Global install (applies to all repos)
bash ~/.copilot/installed-plugins/copilot-skills/codeact/scripts/install-instructions.sh --global
From local checkout (development):
copilot plugin install ./plugins/codeact
bash plugins/codeact/scripts/install-instructions.sh
Backends
| Backend | Runtime | Startup | Python support | Isolation | Requires |
|---|---|---|---|---|---|
| monty (default) | Pydantic Monty | <1μs | Subset (no classes, limited stdlib) | Interpreter-level | Python 3.10+ |
| hyperlight | Hyperlight | ~680ms | Full CPython (Wasm) | Micro-VM | KVM/mshv/Hyper-V, Python ≤3.13 |
Auto-detected at install. Override at install time: --backend monty|hyperlight.
Switch backend:
# Use the management skills
/codeact-install-monty
/codeact-install-hyperlight
# Or directly
bash plugins/codeact/scripts/install-instructions.sh --backend monty
Sandbox Tools
Both backends register tools matching Copilot CLI built-in tool names:
| Tool | What it does | Requires |
|---|---|---|
view | Read files / list directories | — |
create | Create new files | — |
edit | Surgical string replacement | — |
glob | Find files by pattern | — |
bash | Run shell commands | — |
sql | SQLite queries | — |
grep | Search file contents | rg |
web_fetch | Fetch URLs | curl |
github_api | GitHub REST API | gh |
Monty syntax: view(path="README.md") — natural function calls
Hyperlight syntax: call_tool("view", path="README.md") — via wrapper
Customising tools
Both backends consult the same user config (defaults to ~/.config/codeact/,
override with CODEACT_CONFIG_DIR).
Disable built-ins (allowlist or denylist; env wins over config file):
# Denylist via env — drop bash + sql for this session
CODEACT_DISABLE=bash,sql copilot ...
# Allowlist via env — only view/glob/grep registered
CODEACT_TOOLS=view,glob,grep copilot ...
Or persist in ~/.config/codeact/config.json:
{
"disabled": ["bash", "sql"],
"enabled": []
}
After changing config, re-run /codeact-install so the instructions file
- agent prompt reflect the new tool list.
Add your own tools — drop a .py file in ~/.config/codeact/tools/.
File stem becomes the tool name; the file must define a callable (default:
run) plus an optional TOOL metadata dict:
# ~/.config/codeact/tools/shout.py
"""Shout text back in uppercase."""
TOOL = {
"description": "Echo input text in uppercase.",
"parameters": {
"text": {"type": "string", "required": True},
},
# "name": "shout", # optional; defaults to filename stem
# "function": "run", # optional; defaults to "run"
}
def run(text: str = "") -> str:
return text.upper()
After adding, re-run /codeact-install to refresh discovery. Custom tools
also honor allowlist/denylist filters.
Trust: custom tools run on the host with full process privileges (same as built-in
bash). Only install code you trust.
Activation Layers
| Layer | Always-on? | How |
|---|---|---|
| Skill description matching | When prompt matches | Install plugin |
Custom agent (/agent codeact) | Per session | Type once |
Repo instructions (/codeact-install) | In that repo | Run once |
Global instructions (/codeact-install --global) | All sessions | Run once |
PreToolUse enforcement (CODEACT_MODE=nudge|exclusive) | Yes | Set env var |
Layered-activation pattern borrowed from caveman (skill + agent + always-on instructions + tool-call enforcement).
Copilot CLI limitations (vs Claude Code)
Copilot CLI plugin hooks cannot inject system prompts or modify user prompts — only PreToolUse permissionDecision: "deny" reaches the model. So the always-on caveman trick (SessionStart → system context, UserPromptSubmit → per-turn reminder) isn't available, which is why this plugin leans on a self-owned .github/instructions/codeact.instructions.md plus a custom agent. Hook stdout-as-context (parity with Claude Code's additionalContext) would let plugins like this self-activate without writing files.
Testing (developers)
End-to-end harness runs prompts through the real copilot CLI in a temp
workspace and compares baseline vs codeact arms for token / tool-call /
premium-request reduction. Unit tests for the tool-config layer (allow/deny
lists + custom tool loading) live under tests/unit/ and run first via
unittest discover — fast, no copilot CLI needed.
Prerequisites: authenticated copilot CLI, uv (resolves Python + any script deps on demand — no manual pip install). Each perf prompt runs twice (baseline + codeact) so it consumes ~2× premium requests per prompt.
All commands below run from the repo root.
# Unit tests only (no copilot CLI required)
uv run plugins/codeact/tests/run_tests.py unit
# Functional only — auto-creates + cleans up a temp workspace
uv run plugins/codeact/tests/run_tests.py functional
# Perf only — baseline vs codeact comparison (auto workspace)
uv run plugins/codeact/tests/run_tests.py perf
# Full run — unit + preflight + functional + perf + cleanup
uv run plugins/codeact/tests/run_tests.py all
# Keep the temp workspace for inspection (works with all/functional/perf)
uv run plugins/codeact/tests/run_tests.py all --keep-workspace
# Custom token-reduction threshold (default 40%; all + perf)
uv run plugins/codeact/tests/run_tests.py perf --min-token-reduction 30
Reuse an existing workspace (skip auto-create, e.g. when iterating on a fixture):
uv run plugins/codeact/tests/run_tests.py functional \
--workspace /tmp/my-workspace
uv run plugins/codeact/tests/run_tests.py perf \
--workspace /tmp/my-workspace \
--prompts plugins/codeact/tests/prompts/perf.json
Perf results are written to plugins/codeact/tests/results/perf-results-<UTC-timestamp>.json
(plus plugins/codeact/tests/results/perf-results-latest.json as a stable
pointer to the most recent run).
Compare two runs (e.g. before/after a change):
# Auto-compare: latest vs previous run (no args needed)
uv run plugins/codeact/tests/compare_results.py
# Explicit files with labels
uv run plugins/codeact/tests/compare_results.py \
plugins/codeact/tests/results/perf-results-20260424T101500Z.json \
plugins/codeact/tests/results/perf-results-latest.json \
--a-label before --b-label after
# Custom plot output path
uv run plugins/codeact/tests/compare_results.py --out /tmp/diff.png
Without uv, falls back to python3 tests/compare_results.py ... and prints
the delta table only (plot needs pip install matplotlib numpy).
License
MIT
Files in the repo
- .github
- docs
- plugins
- .gitignore
- PLAN.md
- README.md
Discussion (0)
Ask about usage, or say what you built with itSign in to join the discussion.
No comments yet. Be the first to say what this is good for.
More plugins

Graphs that teach > graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.
OmO: Just type "mass ulw" keyword with your prompt. Now you are the master of graph engineering.
Persistent Context Across Sessions for Every Agent – Captures everything your agent does during sessions, compresses it with AI, and injects relevant context back into future sessions. Works with Claude Code, OpenClaw, Codex, Gemini, Hermes, Copilot, OpenCode + More
Opinionated Oxlint rules for rejecting low-evidence TypeScript and JavaScript patterns
Teams-first Multi-agent orchestration for Claude Code