Repository files navigation

agentic-coding

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Note: This is a personal configuration repo, not a reusable tool. Paths and preferences are hardcoded to my environment. Sharing it as reference for others building similar setups.

  • rules.md — shared agent rules referenced by multiple AI coding tools
  • safe.sh + credential-server — sandboxed execution with on-demand credential injection
  • bin/ — CLI wrappers (gh, aws, az, ssh, docker, git-credential-helper) for credential-aware tools inside the sandbox

Rules

rules.md contains cross-repo conventions (commit style, plans, GitHub, etc.) shared across AI coding tools via symlinks and references:

  • ~/AGENTS.md → symlink (Claude Code, general)
  • ~/.claude/CLAUDE.md@ reference (Claude Code)
  • ~/.codex/AGENTS.md@ reference (Codex)
  • ~/.config/opencode/AGENTS.md → symlink (OpenCode)

Sandbox

Run commands inside Agent Safehouse with deny-by-default filesystem access.

# Run any command in the sandbox
./safe.sh <command> [args...]
# Examples
./safe.sh opencode
./safe.sh claude --dangerously-skip-permissions

Credential server

Credentials (gh, aws, git) are injected on-demand via a Unix socket with interactive approval. az uses approval-only gating (no credential injection — it reads tokens from ~/.azure directly). Tokens never live in the sandbox environment — they only exist in the CLI process memory during API calls.

Setup

Start the credential server in a separate terminal:

./credential-server

Then use gh / aws inside the sandbox. Each credential request shows a single-screen form; hotkeys toggle each row in place and Enter confirms. It defaults to once, so a bare Enter allows the single request.

  • scopeo once · r reads (read-only commands) · p pattern (commands matching the chosen pattern) · a all
  • duration (for r/p/a) — 1 1min · 5 5min · s session (until sandbox exits); defaults to 5min
  • pattern (for p with >1 option) — g cycles granularity (e.g. aws s3 cp vs aws s3 vs exact)
  • t — include sensitive (defaults on when the displayed command is itself sensitive)
  • d / Esc — deny

Sensitive commands (secretsmanager/kms/keyvault except list-/describe- metadata ops; ssm only with --with-decryption) are gated separately: a persistent approval without include sensitive still prompts once the first time a sensitive command hits it. Turn the toggle on to pre-consent and skip that later prompt.

Approvals are scoped per-sandbox and per-credential (e.g. approving aws:dev doesn't approve aws:admin; SSH is scoped per-host, so each ssh <host> is approved independently). Only one approval is active per context at a time — selecting a new mode replaces the previous one.

By default, git/gh reads and non-protected-branch pushes are auto-approved without prompting:

  • Reads: git fetch/pull/clone, gh pr list/view/diff, etc.
  • Pushes: git push (not to main/master), gh pr create/edit/close
  • Disable with --no-auto-git-reads or --no-auto-git-push

Additional auto-approvals can be configured in config.toml (not committed):

[auto-approve]
aws-profiles = ["dev", "staging", "*-read"]
main-push-repos = ["myorg/myrepo"]

Listed AWS profiles are auto-approved without prompting, including sensitive commands. Entries may use glob wildcards (*-read, acme-*). Repos listed in main-push-repos (matched against the origin remote) also get pushes to main/master auto-approved. The server prints active auto-approvals on startup.

Extra sandbox settings can be configured in config.toml:

[sandbox]
env-pass = ["OPENCODE_EXPERIMENTAL_LSP_TY"]
allowed-dirs = ["/Users/me/Code/myorg"] # cwd-gated read-write dirsadd-dirs = ["/Users/me/.myapp"] # always read-writeadd-dirs-ro = ["/opt/mytools"] # always read-only

GitHub CLI

./safe.sh gh auth status
./safe.sh gh pr list

AWS CLI

Use --profile to specify the AWS profile. The server fetches temporary STS credentials outside the sandbox and injects them as env vars:

./safe.sh aws --profile dev sts get-caller-identity

Requires an active SSO session (aws sso login --profile <profile> outside the sandbox).

Docker

Docker access is proxied through the credential server — the real Docker socket is never mounted inside the sandbox. The server creates .docker-proxy.sock and forwards approved requests to the host Docker daemon.

./safe.sh docker ps
./safe.sh docker build -t myapp .

SSH

The SSH wrapper strips SSH_AUTH_SOCK by default. Agent access is only restored if approved through the credential server, preventing unauthorized key signing.

Opening URLs

The sandbox can't reach lsd, so bin/open forwards http(s) URLs to the server, which runs the real open outside. Remote hosts get the same via remote/open-url (vendored downstream) over the forwarded socket — useful on a headless box where an agent CLI wants a browser for OAuth. Sandbox opens are silent; remote ones prompt per URL, and an OAuth authorize URL with a loopback redirect_uri also gets an ssh -L tunnel so the callback reaches the remote listener.

Approval persistence

Active approvals are persisted to .approvals.toml and restored on server restart. Expired and stale entries (dead PIDs) are pruned automatically on load.

How it works

  1. credential-server listens on .credential-server.sock outside the sandbox
  2. bin/gh, bin/aws, and bin/git-credential-helper intercept CLI calls inside the sandbox
  3. Wrappers request credentials via JSON protocol, server prompts for approval
  4. If approved, credentials are set as env vars for just that CLI process
  5. Without the server running, CLIs run unauthenticated (no error, just no auth)

About

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

agentic-coding

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Note: This is a personal configuration repo, not a reusable tool. Paths and preferences are hardcoded to my environment. Sharing it as reference for others building similar setups.

  • rules.md — shared agent rules referenced by multiple AI coding tools
  • safe.sh + credential-server — sandboxed execution with on-demand credential injection
  • bin/ — CLI wrappers (gh, aws, az, ssh, docker, git-credential-helper) for credential-aware tools inside the sandbox

Rules

rules.md contains cross-repo conventions (commit style, plans, GitHub, etc.) shared across AI coding tools via symlinks and references:

  • ~/AGENTS.md → symlink (Claude Code, general)
  • ~/.claude/CLAUDE.md@ reference (Claude Code)
  • ~/.codex/AGENTS.md@ reference (Codex)
  • ~/.config/opencode/AGENTS.md → symlink (OpenCode)

Sandbox

Run commands inside Agent Safehouse with deny-by-default filesystem access.

# Run any command in the sandbox
./safe.sh <command> [args...]
# Examples
./safe.sh opencode
./safe.sh claude --dangerously-skip-permissions

Credential server

Credentials (gh, aws, git) are injected on-demand via a Unix socket with interactive approval. az uses approval-only gating (no credential injection — it reads tokens from ~/.azure directly). Tokens never live in the sandbox environment — they only exist in the CLI process memory during API calls.

Setup

Start the credential server in a separate terminal:

./credential-server

Then use gh / aws inside the sandbox. Each credential request shows a single-screen form; hotkeys toggle each row in place and Enter confirms. It defaults to once, so a bare Enter allows the single request.

  • scopeo once · r reads (read-only commands) · p pattern (commands matching the chosen pattern) · a all
  • duration (for r/p/a) — 1 1min · 5 5min · s session (until sandbox exits); defaults to 5min
  • pattern (for p with >1 option) — g cycles granularity (e.g. aws s3 cp vs aws s3 vs exact)
  • t — include sensitive (defaults on when the displayed command is itself sensitive)
  • d / Esc — deny

Sensitive commands (secretsmanager/kms/keyvault except list-/describe- metadata ops; ssm only with --with-decryption) are gated separately: a persistent approval without include sensitive still prompts once the first time a sensitive command hits it. Turn the toggle on to pre-consent and skip that later prompt.

Approvals are scoped per-sandbox and per-credential (e.g. approving aws:dev doesn't approve aws:admin; SSH is scoped per-host, so each ssh <host> is approved independently). Only one approval is active per context at a time — selecting a new mode replaces the previous one.

By default, git/gh reads and non-protected-branch pushes are auto-approved without prompting:

  • Reads: git fetch/pull/clone, gh pr list/view/diff, etc.
  • Pushes: git push (not to main/master), gh pr create/edit/close
  • Disable with --no-auto-git-reads or --no-auto-git-push

Additional auto-approvals can be configured in config.toml (not committed):

[auto-approve]
aws-profiles = ["dev", "staging", "*-read"]
main-push-repos = ["myorg/myrepo"]

Listed AWS profiles are auto-approved without prompting, including sensitive commands. Entries may use glob wildcards (*-read, acme-*). Repos listed in main-push-repos (matched against the origin remote) also get pushes to main/master auto-approved. The server prints active auto-approvals on startup.

Extra sandbox settings can be configured in config.toml:

[sandbox]
env-pass = ["OPENCODE_EXPERIMENTAL_LSP_TY"]
allowed-dirs = ["/Users/me/Code/myorg"] # cwd-gated read-write dirsadd-dirs = ["/Users/me/.myapp"] # always read-writeadd-dirs-ro = ["/opt/mytools"] # always read-only

GitHub CLI

./safe.sh gh auth status
./safe.sh gh pr list

AWS CLI

Use --profile to specify the AWS profile. The server fetches temporary STS credentials outside the sandbox and injects them as env vars:

./safe.sh aws --profile dev sts get-caller-identity

Requires an active SSO session (aws sso login --profile <profile> outside the sandbox).

Docker

Docker access is proxied through the credential server — the real Docker socket is never mounted inside the sandbox. The server creates .docker-proxy.sock and forwards approved requests to the host Docker daemon.

./safe.sh docker ps
./safe.sh docker build -t myapp .

SSH

The SSH wrapper strips SSH_AUTH_SOCK by default. Agent access is only restored if approved through the credential server, preventing unauthorized key signing.

Opening URLs

The sandbox can't reach lsd, so bin/open forwards http(s) URLs to the server, which runs the real open outside. Remote hosts get the same via remote/open-url (vendored downstream) over the forwarded socket — useful on a headless box where an agent CLI wants a browser for OAuth. Sandbox opens are silent; remote ones prompt per URL, and an OAuth authorize URL with a loopback redirect_uri also gets an ssh -L tunnel so the callback reaches the remote listener.

Approval persistence

Active approvals are persisted to .approvals.toml and restored on server restart. Expired and stale entries (dead PIDs) are pruned automatically on load.

How it works

  1. credential-server listens on .credential-server.sock outside the sandbox
  2. bin/gh, bin/aws, and bin/git-credential-helper intercept CLI calls inside the sandbox
  3. Wrappers request credentials via JSON protocol, server prompts for approval
  4. If approved, credentials are set as env vars for just that CLI process
  5. Without the server running, CLIs run unauthenticated (no error, just no auth)

About

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

agentic-coding

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Note: This is a personal configuration repo, not a reusable tool. Paths and preferences are hardcoded to my environment. Sharing it as reference for others building similar setups.

  • rules.md — shared agent rules referenced by multiple AI coding tools
  • safe.sh + credential-server — sandboxed execution with on-demand credential injection
  • bin/ — CLI wrappers (gh, aws, az, ssh, docker, git-credential-helper) for credential-aware tools inside the sandbox

Rules

rules.md contains cross-repo conventions (commit style, plans, GitHub, etc.) shared across AI coding tools via symlinks and references:

  • ~/AGENTS.md → symlink (Claude Code, general)
  • ~/.claude/CLAUDE.md@ reference (Claude Code)
  • ~/.codex/AGENTS.md@ reference (Codex)
  • ~/.config/opencode/AGENTS.md → symlink (OpenCode)

Sandbox

Run commands inside Agent Safehouse with deny-by-default filesystem access.

# Run any command in the sandbox
./safe.sh <command> [args...]
# Examples
./safe.sh opencode
./safe.sh claude --dangerously-skip-permissions

Credential server

Credentials (gh, aws, git) are injected on-demand via a Unix socket with interactive approval. az uses approval-only gating (no credential injection — it reads tokens from ~/.azure directly). Tokens never live in the sandbox environment — they only exist in the CLI process memory during API calls.

Setup

Start the credential server in a separate terminal:

./credential-server

Then use gh / aws inside the sandbox. Each credential request shows a single-screen form; hotkeys toggle each row in place and Enter confirms. It defaults to once, so a bare Enter allows the single request.

  • scopeo once · r reads (read-only commands) · p pattern (commands matching the chosen pattern) · a all
  • duration (for r/p/a) — 1 1min · 5 5min · s session (until sandbox exits); defaults to 5min
  • pattern (for p with >1 option) — g cycles granularity (e.g. aws s3 cp vs aws s3 vs exact)
  • t — include sensitive (defaults on when the displayed command is itself sensitive)
  • d / Esc — deny

Sensitive commands (secretsmanager/kms/keyvault except list-/describe- metadata ops; ssm only with --with-decryption) are gated separately: a persistent approval without include sensitive still prompts once the first time a sensitive command hits it. Turn the toggle on to pre-consent and skip that later prompt.

Approvals are scoped per-sandbox and per-credential (e.g. approving aws:dev doesn't approve aws:admin; SSH is scoped per-host, so each ssh <host> is approved independently). Only one approval is active per context at a time — selecting a new mode replaces the previous one.

By default, git/gh reads and non-protected-branch pushes are auto-approved without prompting:

  • Reads: git fetch/pull/clone, gh pr list/view/diff, etc.
  • Pushes: git push (not to main/master), gh pr create/edit/close
  • Disable with --no-auto-git-reads or --no-auto-git-push

Additional auto-approvals can be configured in config.toml (not committed):

[auto-approve]
aws-profiles = ["dev", "staging", "*-read"]
main-push-repos = ["myorg/myrepo"]

Listed AWS profiles are auto-approved without prompting, including sensitive commands. Entries may use glob wildcards (*-read, acme-*). Repos listed in main-push-repos (matched against the origin remote) also get pushes to main/master auto-approved. The server prints active auto-approvals on startup.

Extra sandbox settings can be configured in config.toml:

[sandbox]
env-pass = ["OPENCODE_EXPERIMENTAL_LSP_TY"]
allowed-dirs = ["/Users/me/Code/myorg"] # cwd-gated read-write dirsadd-dirs = ["/Users/me/.myapp"] # always read-writeadd-dirs-ro = ["/opt/mytools"] # always read-only

GitHub CLI

./safe.sh gh auth status
./safe.sh gh pr list

AWS CLI

Use --profile to specify the AWS profile. The server fetches temporary STS credentials outside the sandbox and injects them as env vars:

./safe.sh aws --profile dev sts get-caller-identity

Requires an active SSO session (aws sso login --profile <profile> outside the sandbox).

Docker

Docker access is proxied through the credential server — the real Docker socket is never mounted inside the sandbox. The server creates .docker-proxy.sock and forwards approved requests to the host Docker daemon.

./safe.sh docker ps
./safe.sh docker build -t myapp .

SSH

The SSH wrapper strips SSH_AUTH_SOCK by default. Agent access is only restored if approved through the credential server, preventing unauthorized key signing.

Opening URLs

The sandbox can't reach lsd, so bin/open forwards http(s) URLs to the server, which runs the real open outside. Remote hosts get the same via remote/open-url (vendored downstream) over the forwarded socket — useful on a headless box where an agent CLI wants a browser for OAuth. Sandbox opens are silent; remote ones prompt per URL, and an OAuth authorize URL with a loopback redirect_uri also gets an ssh -L tunnel so the callback reaches the remote listener.

Approval persistence

Active approvals are persisted to .approvals.toml and restored on server restart. Expired and stale entries (dead PIDs) are pruned automatically on load.

How it works

  1. credential-server listens on .credential-server.sock outside the sandbox
  2. bin/gh, bin/aws, and bin/git-credential-helper intercept CLI calls inside the sandbox
  3. Wrappers request credentials via JSON protocol, server prompts for approval
  4. If approved, credentials are set as env vars for just that CLI process
  5. Without the server running, CLIs run unauthenticated (no error, just no auth)

About

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

agentic-coding

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Note: This is a personal configuration repo, not a reusable tool. Paths and preferences are hardcoded to my environment. Sharing it as reference for others building similar setups.

  • rules.md — shared agent rules referenced by multiple AI coding tools
  • safe.sh + credential-server — sandboxed execution with on-demand credential injection
  • bin/ — CLI wrappers (gh, aws, az, ssh, docker, git-credential-helper) for credential-aware tools inside the sandbox

Rules

rules.md contains cross-repo conventions (commit style, plans, GitHub, etc.) shared across AI coding tools via symlinks and references:

  • ~/AGENTS.md → symlink (Claude Code, general)
  • ~/.claude/CLAUDE.md@ reference (Claude Code)
  • ~/.codex/AGENTS.md@ reference (Codex)
  • ~/.config/opencode/AGENTS.md → symlink (OpenCode)

Sandbox

Run commands inside Agent Safehouse with deny-by-default filesystem access.

# Run any command in the sandbox
./safe.sh <command> [args...]
# Examples
./safe.sh opencode
./safe.sh claude --dangerously-skip-permissions

Credential server

Credentials (gh, aws, git) are injected on-demand via a Unix socket with interactive approval. az uses approval-only gating (no credential injection — it reads tokens from ~/.azure directly). Tokens never live in the sandbox environment — they only exist in the CLI process memory during API calls.

Setup

Start the credential server in a separate terminal:

./credential-server

Then use gh / aws inside the sandbox. Each credential request shows a single-screen form; hotkeys toggle each row in place and Enter confirms. It defaults to once, so a bare Enter allows the single request.

  • scopeo once · r reads (read-only commands) · p pattern (commands matching the chosen pattern) · a all
  • duration (for r/p/a) — 1 1min · 5 5min · s session (until sandbox exits); defaults to 5min
  • pattern (for p with >1 option) — g cycles granularity (e.g. aws s3 cp vs aws s3 vs exact)
  • t — include sensitive (defaults on when the displayed command is itself sensitive)
  • d / Esc — deny

Sensitive commands (secretsmanager/kms/keyvault except list-/describe- metadata ops; ssm only with --with-decryption) are gated separately: a persistent approval without include sensitive still prompts once the first time a sensitive command hits it. Turn the toggle on to pre-consent and skip that later prompt.

Approvals are scoped per-sandbox and per-credential (e.g. approving aws:dev doesn't approve aws:admin; SSH is scoped per-host, so each ssh <host> is approved independently). Only one approval is active per context at a time — selecting a new mode replaces the previous one.

By default, git/gh reads and non-protected-branch pushes are auto-approved without prompting:

  • Reads: git fetch/pull/clone, gh pr list/view/diff, etc.
  • Pushes: git push (not to main/master), gh pr create/edit/close
  • Disable with --no-auto-git-reads or --no-auto-git-push

Additional auto-approvals can be configured in config.toml (not committed):

[auto-approve]
aws-profiles = ["dev", "staging", "*-read"]
main-push-repos = ["myorg/myrepo"]

Listed AWS profiles are auto-approved without prompting, including sensitive commands. Entries may use glob wildcards (*-read, acme-*). Repos listed in main-push-repos (matched against the origin remote) also get pushes to main/master auto-approved. The server prints active auto-approvals on startup.

Extra sandbox settings can be configured in config.toml:

[sandbox]
env-pass = ["OPENCODE_EXPERIMENTAL_LSP_TY"]
allowed-dirs = ["/Users/me/Code/myorg"] # cwd-gated read-write dirsadd-dirs = ["/Users/me/.myapp"] # always read-writeadd-dirs-ro = ["/opt/mytools"] # always read-only

GitHub CLI

./safe.sh gh auth status
./safe.sh gh pr list

AWS CLI

Use --profile to specify the AWS profile. The server fetches temporary STS credentials outside the sandbox and injects them as env vars:

./safe.sh aws --profile dev sts get-caller-identity

Requires an active SSO session (aws sso login --profile <profile> outside the sandbox).

Docker

Docker access is proxied through the credential server — the real Docker socket is never mounted inside the sandbox. The server creates .docker-proxy.sock and forwards approved requests to the host Docker daemon.

./safe.sh docker ps
./safe.sh docker build -t myapp .

SSH

The SSH wrapper strips SSH_AUTH_SOCK by default. Agent access is only restored if approved through the credential server, preventing unauthorized key signing.

Opening URLs

The sandbox can't reach lsd, so bin/open forwards http(s) URLs to the server, which runs the real open outside. Remote hosts get the same via remote/open-url (vendored downstream) over the forwarded socket — useful on a headless box where an agent CLI wants a browser for OAuth. Sandbox opens are silent; remote ones prompt per URL, and an OAuth authorize URL with a loopback redirect_uri also gets an ssh -L tunnel so the callback reaches the remote listener.

Approval persistence

Active approvals are persisted to .approvals.toml and restored on server restart. Expired and stale entries (dead PIDs) are pruned automatically on load.

How it works

  1. credential-server listens on .credential-server.sock outside the sandbox
  2. bin/gh, bin/aws, and bin/git-credential-helper intercept CLI calls inside the sandbox
  3. Wrappers request credentials via JSON protocol, server prompts for approval
  4. If approved, credentials are set as env vars for just that CLI process
  5. Without the server running, CLIs run unauthenticated (no error, just no auth)

About

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

agentic-coding

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Note: This is a personal configuration repo, not a reusable tool. Paths and preferences are hardcoded to my environment. Sharing it as reference for others building similar setups.

  • rules.md — shared agent rules referenced by multiple AI coding tools
  • safe.sh + credential-server — sandboxed execution with on-demand credential injection
  • bin/ — CLI wrappers (gh, aws, az, ssh, docker, git-credential-helper) for credential-aware tools inside the sandbox

Rules

rules.md contains cross-repo conventions (commit style, plans, GitHub, etc.) shared across AI coding tools via symlinks and references:

  • ~/AGENTS.md → symlink (Claude Code, general)
  • ~/.claude/CLAUDE.md@ reference (Claude Code)
  • ~/.codex/AGENTS.md@ reference (Codex)
  • ~/.config/opencode/AGENTS.md → symlink (OpenCode)

Sandbox

Run commands inside Agent Safehouse with deny-by-default filesystem access.

# Run any command in the sandbox
./safe.sh <command> [args...]
# Examples
./safe.sh opencode
./safe.sh claude --dangerously-skip-permissions

Credential server

Credentials (gh, aws, git) are injected on-demand via a Unix socket with interactive approval. az uses approval-only gating (no credential injection — it reads tokens from ~/.azure directly). Tokens never live in the sandbox environment — they only exist in the CLI process memory during API calls.

Setup

Start the credential server in a separate terminal:

./credential-server

Then use gh / aws inside the sandbox. Each credential request shows a single-screen form; hotkeys toggle each row in place and Enter confirms. It defaults to once, so a bare Enter allows the single request.

  • scopeo once · r reads (read-only commands) · p pattern (commands matching the chosen pattern) · a all
  • duration (for r/p/a) — 1 1min · 5 5min · s session (until sandbox exits); defaults to 5min
  • pattern (for p with >1 option) — g cycles granularity (e.g. aws s3 cp vs aws s3 vs exact)
  • t — include sensitive (defaults on when the displayed command is itself sensitive)
  • d / Esc — deny

Sensitive commands (secretsmanager/kms/keyvault except list-/describe- metadata ops; ssm only with --with-decryption) are gated separately: a persistent approval without include sensitive still prompts once the first time a sensitive command hits it. Turn the toggle on to pre-consent and skip that later prompt.

Approvals are scoped per-sandbox and per-credential (e.g. approving aws:dev doesn't approve aws:admin; SSH is scoped per-host, so each ssh <host> is approved independently). Only one approval is active per context at a time — selecting a new mode replaces the previous one.

By default, git/gh reads and non-protected-branch pushes are auto-approved without prompting:

  • Reads: git fetch/pull/clone, gh pr list/view/diff, etc.
  • Pushes: git push (not to main/master), gh pr create/edit/close
  • Disable with --no-auto-git-reads or --no-auto-git-push

Additional auto-approvals can be configured in config.toml (not committed):

[auto-approve]
aws-profiles = ["dev", "staging", "*-read"]
main-push-repos = ["myorg/myrepo"]

Listed AWS profiles are auto-approved without prompting, including sensitive commands. Entries may use glob wildcards (*-read, acme-*). Repos listed in main-push-repos (matched against the origin remote) also get pushes to main/master auto-approved. The server prints active auto-approvals on startup.

Extra sandbox settings can be configured in config.toml:

[sandbox]
env-pass = ["OPENCODE_EXPERIMENTAL_LSP_TY"]
allowed-dirs = ["/Users/me/Code/myorg"] # cwd-gated read-write dirsadd-dirs = ["/Users/me/.myapp"] # always read-writeadd-dirs-ro = ["/opt/mytools"] # always read-only

GitHub CLI

./safe.sh gh auth status
./safe.sh gh pr list

AWS CLI

Use --profile to specify the AWS profile. The server fetches temporary STS credentials outside the sandbox and injects them as env vars:

./safe.sh aws --profile dev sts get-caller-identity

Requires an active SSO session (aws sso login --profile <profile> outside the sandbox).

Docker

Docker access is proxied through the credential server — the real Docker socket is never mounted inside the sandbox. The server creates .docker-proxy.sock and forwards approved requests to the host Docker daemon.

./safe.sh docker ps
./safe.sh docker build -t myapp .

SSH

The SSH wrapper strips SSH_AUTH_SOCK by default. Agent access is only restored if approved through the credential server, preventing unauthorized key signing.

Opening URLs

The sandbox can't reach lsd, so bin/open forwards http(s) URLs to the server, which runs the real open outside. Remote hosts get the same via remote/open-url (vendored downstream) over the forwarded socket — useful on a headless box where an agent CLI wants a browser for OAuth. Sandbox opens are silent; remote ones prompt per URL, and an OAuth authorize URL with a loopback redirect_uri also gets an ssh -L tunnel so the callback reaches the remote listener.

Approval persistence

Active approvals are persisted to .approvals.toml and restored on server restart. Expired and stale entries (dead PIDs) are pruned automatically on load.

How it works

  1. credential-server listens on .credential-server.sock outside the sandbox
  2. bin/gh, bin/aws, and bin/git-credential-helper intercept CLI calls inside the sandbox
  3. Wrappers request credentials via JSON protocol, server prompts for approval
  4. If approved, credentials are set as env vars for just that CLI process
  5. Without the server running, CLIs run unauthenticated (no error, just no auth)

About

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

agentic-coding

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Note: This is a personal configuration repo, not a reusable tool. Paths and preferences are hardcoded to my environment. Sharing it as reference for others building similar setups.

  • rules.md — shared agent rules referenced by multiple AI coding tools
  • safe.sh + credential-server — sandboxed execution with on-demand credential injection
  • bin/ — CLI wrappers (gh, aws, az, ssh, docker, git-credential-helper) for credential-aware tools inside the sandbox

Rules

rules.md contains cross-repo conventions (commit style, plans, GitHub, etc.) shared across AI coding tools via symlinks and references:

  • ~/AGENTS.md → symlink (Claude Code, general)
  • ~/.claude/CLAUDE.md@ reference (Claude Code)
  • ~/.codex/AGENTS.md@ reference (Codex)
  • ~/.config/opencode/AGENTS.md → symlink (OpenCode)

Sandbox

Run commands inside Agent Safehouse with deny-by-default filesystem access.

# Run any command in the sandbox
./safe.sh <command> [args...]
# Examples
./safe.sh opencode
./safe.sh claude --dangerously-skip-permissions

Credential server

Credentials (gh, aws, git) are injected on-demand via a Unix socket with interactive approval. az uses approval-only gating (no credential injection — it reads tokens from ~/.azure directly). Tokens never live in the sandbox environment — they only exist in the CLI process memory during API calls.

Setup

Start the credential server in a separate terminal:

./credential-server

Then use gh / aws inside the sandbox. Each credential request shows a single-screen form; hotkeys toggle each row in place and Enter confirms. It defaults to once, so a bare Enter allows the single request.

  • scopeo once · r reads (read-only commands) · p pattern (commands matching the chosen pattern) · a all
  • duration (for r/p/a) — 1 1min · 5 5min · s session (until sandbox exits); defaults to 5min
  • pattern (for p with >1 option) — g cycles granularity (e.g. aws s3 cp vs aws s3 vs exact)
  • t — include sensitive (defaults on when the displayed command is itself sensitive)
  • d / Esc — deny

Sensitive commands (secretsmanager/kms/keyvault except list-/describe- metadata ops; ssm only with --with-decryption) are gated separately: a persistent approval without include sensitive still prompts once the first time a sensitive command hits it. Turn the toggle on to pre-consent and skip that later prompt.

Approvals are scoped per-sandbox and per-credential (e.g. approving aws:dev doesn't approve aws:admin; SSH is scoped per-host, so each ssh <host> is approved independently). Only one approval is active per context at a time — selecting a new mode replaces the previous one.

By default, git/gh reads and non-protected-branch pushes are auto-approved without prompting:

  • Reads: git fetch/pull/clone, gh pr list/view/diff, etc.
  • Pushes: git push (not to main/master), gh pr create/edit/close
  • Disable with --no-auto-git-reads or --no-auto-git-push

Additional auto-approvals can be configured in config.toml (not committed):

[auto-approve]
aws-profiles = ["dev", "staging", "*-read"]
main-push-repos = ["myorg/myrepo"]

Listed AWS profiles are auto-approved without prompting, including sensitive commands. Entries may use glob wildcards (*-read, acme-*). Repos listed in main-push-repos (matched against the origin remote) also get pushes to main/master auto-approved. The server prints active auto-approvals on startup.

Extra sandbox settings can be configured in config.toml:

[sandbox]
env-pass = ["OPENCODE_EXPERIMENTAL_LSP_TY"]
allowed-dirs = ["/Users/me/Code/myorg"] # cwd-gated read-write dirsadd-dirs = ["/Users/me/.myapp"] # always read-writeadd-dirs-ro = ["/opt/mytools"] # always read-only

GitHub CLI

./safe.sh gh auth status
./safe.sh gh pr list

AWS CLI

Use --profile to specify the AWS profile. The server fetches temporary STS credentials outside the sandbox and injects them as env vars:

./safe.sh aws --profile dev sts get-caller-identity

Requires an active SSO session (aws sso login --profile <profile> outside the sandbox).

Docker

Docker access is proxied through the credential server — the real Docker socket is never mounted inside the sandbox. The server creates .docker-proxy.sock and forwards approved requests to the host Docker daemon.

./safe.sh docker ps
./safe.sh docker build -t myapp .

SSH

The SSH wrapper strips SSH_AUTH_SOCK by default. Agent access is only restored if approved through the credential server, preventing unauthorized key signing.

Opening URLs

The sandbox can't reach lsd, so bin/open forwards http(s) URLs to the server, which runs the real open outside. Remote hosts get the same via remote/open-url (vendored downstream) over the forwarded socket — useful on a headless box where an agent CLI wants a browser for OAuth. Sandbox opens are silent; remote ones prompt per URL, and an OAuth authorize URL with a loopback redirect_uri also gets an ssh -L tunnel so the callback reaches the remote listener.

Approval persistence

Active approvals are persisted to .approvals.toml and restored on server restart. Expired and stale entries (dead PIDs) are pruned automatically on load.

How it works

  1. credential-server listens on .credential-server.sock outside the sandbox
  2. bin/gh, bin/aws, and bin/git-credential-helper intercept CLI calls inside the sandbox
  3. Wrappers request credentials via JSON protocol, server prompts for approval
  4. If approved, credentials are set as env vars for just that CLI process
  5. Without the server running, CLIs run unauthenticated (no error, just no auth)

About

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

agentic-coding

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Note: This is a personal configuration repo, not a reusable tool. Paths and preferences are hardcoded to my environment. Sharing it as reference for others building similar setups.

  • rules.md — shared agent rules referenced by multiple AI coding tools
  • safe.sh + credential-server — sandboxed execution with on-demand credential injection
  • bin/ — CLI wrappers (gh, aws, az, ssh, docker, git-credential-helper) for credential-aware tools inside the sandbox

Rules

rules.md contains cross-repo conventions (commit style, plans, GitHub, etc.) shared across AI coding tools via symlinks and references:

  • ~/AGENTS.md → symlink (Claude Code, general)
  • ~/.claude/CLAUDE.md@ reference (Claude Code)
  • ~/.codex/AGENTS.md@ reference (Codex)
  • ~/.config/opencode/AGENTS.md → symlink (OpenCode)

Sandbox

Run commands inside Agent Safehouse with deny-by-default filesystem access.

# Run any command in the sandbox
./safe.sh <command> [args...]
# Examples
./safe.sh opencode
./safe.sh claude --dangerously-skip-permissions

Credential server

Credentials (gh, aws, git) are injected on-demand via a Unix socket with interactive approval. az uses approval-only gating (no credential injection — it reads tokens from ~/.azure directly). Tokens never live in the sandbox environment — they only exist in the CLI process memory during API calls.

Setup

Start the credential server in a separate terminal:

./credential-server

Then use gh / aws inside the sandbox. Each credential request shows a single-screen form; hotkeys toggle each row in place and Enter confirms. It defaults to once, so a bare Enter allows the single request.

  • scopeo once · r reads (read-only commands) · p pattern (commands matching the chosen pattern) · a all
  • duration (for r/p/a) — 1 1min · 5 5min · s session (until sandbox exits); defaults to 5min
  • pattern (for p with >1 option) — g cycles granularity (e.g. aws s3 cp vs aws s3 vs exact)
  • t — include sensitive (defaults on when the displayed command is itself sensitive)
  • d / Esc — deny

Sensitive commands (secretsmanager/kms/keyvault except list-/describe- metadata ops; ssm only with --with-decryption) are gated separately: a persistent approval without include sensitive still prompts once the first time a sensitive command hits it. Turn the toggle on to pre-consent and skip that later prompt.

Approvals are scoped per-sandbox and per-credential (e.g. approving aws:dev doesn't approve aws:admin; SSH is scoped per-host, so each ssh <host> is approved independently). Only one approval is active per context at a time — selecting a new mode replaces the previous one.

By default, git/gh reads and non-protected-branch pushes are auto-approved without prompting:

  • Reads: git fetch/pull/clone, gh pr list/view/diff, etc.
  • Pushes: git push (not to main/master), gh pr create/edit/close
  • Disable with --no-auto-git-reads or --no-auto-git-push

Additional auto-approvals can be configured in config.toml (not committed):

[auto-approve]
aws-profiles = ["dev", "staging", "*-read"]
main-push-repos = ["myorg/myrepo"]

Listed AWS profiles are auto-approved without prompting, including sensitive commands. Entries may use glob wildcards (*-read, acme-*). Repos listed in main-push-repos (matched against the origin remote) also get pushes to main/master auto-approved. The server prints active auto-approvals on startup.

Extra sandbox settings can be configured in config.toml:

[sandbox]
env-pass = ["OPENCODE_EXPERIMENTAL_LSP_TY"]
allowed-dirs = ["/Users/me/Code/myorg"] # cwd-gated read-write dirsadd-dirs = ["/Users/me/.myapp"] # always read-writeadd-dirs-ro = ["/opt/mytools"] # always read-only

GitHub CLI

./safe.sh gh auth status
./safe.sh gh pr list

AWS CLI

Use --profile to specify the AWS profile. The server fetches temporary STS credentials outside the sandbox and injects them as env vars:

./safe.sh aws --profile dev sts get-caller-identity

Requires an active SSO session (aws sso login --profile <profile> outside the sandbox).

Docker

Docker access is proxied through the credential server — the real Docker socket is never mounted inside the sandbox. The server creates .docker-proxy.sock and forwards approved requests to the host Docker daemon.

./safe.sh docker ps
./safe.sh docker build -t myapp .

SSH

The SSH wrapper strips SSH_AUTH_SOCK by default. Agent access is only restored if approved through the credential server, preventing unauthorized key signing.

Opening URLs

The sandbox can't reach lsd, so bin/open forwards http(s) URLs to the server, which runs the real open outside. Remote hosts get the same via remote/open-url (vendored downstream) over the forwarded socket — useful on a headless box where an agent CLI wants a browser for OAuth. Sandbox opens are silent; remote ones prompt per URL, and an OAuth authorize URL with a loopback redirect_uri also gets an ssh -L tunnel so the callback reaches the remote listener.

Approval persistence

Active approvals are persisted to .approvals.toml and restored on server restart. Expired and stale entries (dead PIDs) are pruned automatically on load.

How it works

  1. credential-server listens on .credential-server.sock outside the sandbox
  2. bin/gh, bin/aws, and bin/git-credential-helper intercept CLI calls inside the sandbox
  3. Wrappers request credentials via JSON protocol, server prompts for approval
  4. If approved, credentials are set as env vars for just that CLI process
  5. Without the server running, CLIs run unauthenticated (no error, just no auth)

About

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

agentic-coding

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Note: This is a personal configuration repo, not a reusable tool. Paths and preferences are hardcoded to my environment. Sharing it as reference for others building similar setups.

  • rules.md — shared agent rules referenced by multiple AI coding tools
  • safe.sh + credential-server — sandboxed execution with on-demand credential injection
  • bin/ — CLI wrappers (gh, aws, az, ssh, docker, git-credential-helper) for credential-aware tools inside the sandbox

Rules

rules.md contains cross-repo conventions (commit style, plans, GitHub, etc.) shared across AI coding tools via symlinks and references:

  • ~/AGENTS.md → symlink (Claude Code, general)
  • ~/.claude/CLAUDE.md@ reference (Claude Code)
  • ~/.codex/AGENTS.md@ reference (Codex)
  • ~/.config/opencode/AGENTS.md → symlink (OpenCode)

Sandbox

Run commands inside Agent Safehouse with deny-by-default filesystem access.

# Run any command in the sandbox
./safe.sh <command> [args...]
# Examples
./safe.sh opencode
./safe.sh claude --dangerously-skip-permissions

Credential server

Credentials (gh, aws, git) are injected on-demand via a Unix socket with interactive approval. az uses approval-only gating (no credential injection — it reads tokens from ~/.azure directly). Tokens never live in the sandbox environment — they only exist in the CLI process memory during API calls.

Setup

Start the credential server in a separate terminal:

./credential-server

Then use gh / aws inside the sandbox. Each credential request shows a single-screen form; hotkeys toggle each row in place and Enter confirms. It defaults to once, so a bare Enter allows the single request.

  • scopeo once · r reads (read-only commands) · p pattern (commands matching the chosen pattern) · a all
  • duration (for r/p/a) — 1 1min · 5 5min · s session (until sandbox exits); defaults to 5min
  • pattern (for p with >1 option) — g cycles granularity (e.g. aws s3 cp vs aws s3 vs exact)
  • t — include sensitive (defaults on when the displayed command is itself sensitive)
  • d / Esc — deny

Sensitive commands (secretsmanager/kms/keyvault except list-/describe- metadata ops; ssm only with --with-decryption) are gated separately: a persistent approval without include sensitive still prompts once the first time a sensitive command hits it. Turn the toggle on to pre-consent and skip that later prompt.

Approvals are scoped per-sandbox and per-credential (e.g. approving aws:dev doesn't approve aws:admin; SSH is scoped per-host, so each ssh <host> is approved independently). Only one approval is active per context at a time — selecting a new mode replaces the previous one.

By default, git/gh reads and non-protected-branch pushes are auto-approved without prompting:

  • Reads: git fetch/pull/clone, gh pr list/view/diff, etc.
  • Pushes: git push (not to main/master), gh pr create/edit/close
  • Disable with --no-auto-git-reads or --no-auto-git-push

Additional auto-approvals can be configured in config.toml (not committed):

[auto-approve]
aws-profiles = ["dev", "staging", "*-read"]
main-push-repos = ["myorg/myrepo"]

Listed AWS profiles are auto-approved without prompting, including sensitive commands. Entries may use glob wildcards (*-read, acme-*). Repos listed in main-push-repos (matched against the origin remote) also get pushes to main/master auto-approved. The server prints active auto-approvals on startup.

Extra sandbox settings can be configured in config.toml:

[sandbox]
env-pass = ["OPENCODE_EXPERIMENTAL_LSP_TY"]
allowed-dirs = ["/Users/me/Code/myorg"] # cwd-gated read-write dirsadd-dirs = ["/Users/me/.myapp"] # always read-writeadd-dirs-ro = ["/opt/mytools"] # always read-only

GitHub CLI

./safe.sh gh auth status
./safe.sh gh pr list

AWS CLI

Use --profile to specify the AWS profile. The server fetches temporary STS credentials outside the sandbox and injects them as env vars:

./safe.sh aws --profile dev sts get-caller-identity

Requires an active SSO session (aws sso login --profile <profile> outside the sandbox).

Docker

Docker access is proxied through the credential server — the real Docker socket is never mounted inside the sandbox. The server creates .docker-proxy.sock and forwards approved requests to the host Docker daemon.

./safe.sh docker ps
./safe.sh docker build -t myapp .

SSH

The SSH wrapper strips SSH_AUTH_SOCK by default. Agent access is only restored if approved through the credential server, preventing unauthorized key signing.

Opening URLs

The sandbox can't reach lsd, so bin/open forwards http(s) URLs to the server, which runs the real open outside. Remote hosts get the same via remote/open-url (vendored downstream) over the forwarded socket — useful on a headless box where an agent CLI wants a browser for OAuth. Sandbox opens are silent; remote ones prompt per URL, and an OAuth authorize URL with a loopback redirect_uri also gets an ssh -L tunnel so the callback reaches the remote listener.

Approval persistence

Active approvals are persisted to .approvals.toml and restored on server restart. Expired and stale entries (dead PIDs) are pruned automatically on load.

How it works

  1. credential-server listens on .credential-server.sock outside the sandbox
  2. bin/gh, bin/aws, and bin/git-credential-helper intercept CLI calls inside the sandbox
  3. Wrappers request credentials via JSON protocol, server prompts for approval
  4. If approved, credentials are set as env vars for just that CLI process
  5. Without the server running, CLIs run unauthenticated (no error, just no auth)

About

My personal setup for sandboxed agentic coding — sandbox tooling, credential injection, and shared agent rules.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages