Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
package-lock.json
dist/
*.log
.DS_Store
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

All notable changes to `@inceptionstack/pi-branch-enforcer` are documented here.

## [3.3.0] — 2026-05-14

### Added
- **Runtime kill-switch** — enforcement can now be disabled without restarting the agent
- File-based: create `~/.pi-branch-enforcer/disabled` to disable; remove to re-enable
- Env var: `PI_BRANCH_ENFORCER_DISABLED=1` (process-scope only)
- Checked on every `tool_call`, so toggling takes effect on the next bash command
- Designed for use with roundhouse `/toggle-enforce-branches` (immediate, persisted across restarts)

## [3.2.1] — 2026-05-10

### Fixed
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ Detects when a scripting language executes a file (e.g. `node /tmp/script.js`):

None needed. Works out of the box. Protected branches are `main` and `master`.

## Disabling at runtime

The extension honors a runtime kill-switch — useful when an automation needs
to temporarily bypass enforcement (e.g. release scripts, recovery scenarios)
without restarting the agent.

**File-based (persistent):**
```bash
# Disable
mkdir -p ~/.pi-branch-enforcer && touch ~/.pi-branch-enforcer/disabled

# Re-enable
rm ~/.pi-branch-enforcer/disabled
```

**Env var (process-scope only):**
```bash
PI_BRANCH_ENFORCER_DISABLED=1 pi ...
```

The file is checked on every `bash` tool call, so toggling takes effect on
the **next** command — no agent restart required. Roundhouse exposes this
as the `/toggle-enforce-branches` Telegram command.

## License

Apache-2.0
23 changes: 23 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,30 @@
*/

import { type ExtensionAPI, isToolCallEventType } from "@earendil-works/pi-coding-agent";
import { existsSync } from "node:fs";
import { join } from "node:path";
import { homedir } from "node:os";

/** Branch names that are protected from direct commits and pushes. */
const PROTECTED_BRANCHES = new Set(["main", "master"]);

/**
* Runtime kill-switch path. If this file exists OR the env var
* `PI_BRANCH_ENFORCER_DISABLED=1` is set, the extension fails open
* (returns immediately on every tool_call). Lets external tooling
* (e.g. roundhouse `/toggle-enforce-branches`) disable enforcement
* without restarting the agent.
*
* File-based switch is preferred over env var because it survives
* agent restarts and works for already-running processes.
*/
const DISABLED_MARKER_PATH = join(homedir(), ".pi-branch-enforcer", "disabled");

function isDisabled(): boolean {
if (process.env.PI_BRANCH_ENFORCER_DISABLED === "1") return true;
try { return existsSync(DISABLED_MARKER_PATH); } catch { return false; }
}

const BRANCH_FIX_INSTRUCTIONS =
`Use a feature branch for all changes.\n\n` +
`To fix:\n` +
Expand All @@ -34,6 +54,9 @@ const JUDGE_MODEL = "us.anthropic.claude-haiku-4-5-20251001-v1:0";
export default function (pi: ExtensionAPI) {
pi.on("tool_call", async (event, ctx) => {
if (!isToolCallEventType("bash", event)) return;
// Runtime kill-switch — checked on every call so toggling takes effect
// immediately without restarting the agent.
if (isDisabled()) return;
const cmd = event.input.command ?? "";

// Tier 1: Fast regex for direct git commands
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@inceptionstack/pi-branch-enforcer",
"version": "3.2.2",
"version": "3.3.0",
"description": "Pi extension — prevents git commit/push directly to main/master, enforces branch workflow",
"keywords": [
"pi",
Expand Down