4 files changed,
+294,
-0
+61,
-0
1@@ -0,0 +1,61 @@
2+{
3+ "nodes": {
4+ "flake-utils": {
5+ "inputs": {
6+ "systems": "systems"
7+ },
8+ "locked": {
9+ "lastModified": 1731533236,
10+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
11+ "owner": "numtide",
12+ "repo": "flake-utils",
13+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
14+ "type": "github"
15+ },
16+ "original": {
17+ "owner": "numtide",
18+ "repo": "flake-utils",
19+ "type": "github"
20+ }
21+ },
22+ "nixpkgs": {
23+ "locked": {
24+ "lastModified": 1777268161,
25+ "narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=",
26+ "owner": "NixOS",
27+ "repo": "nixpkgs",
28+ "rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76",
29+ "type": "github"
30+ },
31+ "original": {
32+ "owner": "NixOS",
33+ "ref": "nixos-unstable",
34+ "repo": "nixpkgs",
35+ "type": "github"
36+ }
37+ },
38+ "root": {
39+ "inputs": {
40+ "flake-utils": "flake-utils",
41+ "nixpkgs": "nixpkgs"
42+ }
43+ },
44+ "systems": {
45+ "locked": {
46+ "lastModified": 1681028828,
47+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
48+ "owner": "nix-systems",
49+ "repo": "default",
50+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
51+ "type": "github"
52+ },
53+ "original": {
54+ "owner": "nix-systems",
55+ "repo": "default",
56+ "type": "github"
57+ }
58+ }
59+ },
60+ "root": "root",
61+ "version": 7
62+}
+107,
-0
1@@ -0,0 +1,107 @@
2+{
3+ description = "Vibe - Sandboxed OpenCode runner with firejail isolation";
4+
5+ inputs = {
6+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
7+ flake-utils.url = "github:numtide/flake-utils";
8+ };
9+
10+ outputs = { self, nixpkgs, flake-utils }:
11+ flake-utils.lib.eachDefaultSystem (system:
12+ let
13+ pkgs = nixpkgs.legacyPackages.${system};
14+
15+ # jail package - wraps jail.sh with firejail dependency
16+ jail = pkgs.stdenvNoCC.mkDerivation {
17+ pname = "jail";
18+ version = "0.1.0";
19+
20+ src = ./.;
21+
22+ nativeBuildInputs = [ pkgs.makeWrapper ];
23+
24+ buildInputs = [ pkgs.firejail ];
25+
26+ installPhase = ''
27+ runHook preInstall
28+
29+ mkdir -p $out/bin
30+ cp jail.sh $out/bin/jail
31+ chmod +x $out/bin/jail
32+
33+ # Wrap jail to ensure firejail is in PATH
34+ wrapProgram $out/bin/jail \
35+ --prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.firejail pkgs.git pkgs.coreutils pkgs.which ]}
36+
37+ runHook postInstall
38+ '';
39+
40+ meta = with pkgs.lib; {
41+ description = "Run OpenCode in a sandboxed firejail environment";
42+ homepage = "https://kilimanjaro.io/vibe";
43+ license = licenses.mit;
44+ platforms = platforms.linux;
45+ };
46+ };
47+
48+ # vibe package - wraps jail opencode
49+ vibe = pkgs.stdenvNoCC.mkDerivation {
50+ pname = "vibe";
51+ version = "0.1.0";
52+
53+ src = ./.;
54+
55+ nativeBuildInputs = [ pkgs.makeWrapper ];
56+
57+ buildInputs = [ jail pkgs.opencode ];
58+
59+ installPhase = ''
60+ runHook preInstall
61+
62+ mkdir -p $out/bin
63+ cp vibe.sh $out/bin/vibe
64+ chmod +x $out/bin/vibe
65+
66+ # Wrap vibe to ensure jail and opencode are in PATH
67+ wrapProgram $out/bin/vibe \
68+ --prefix PATH : ${pkgs.lib.makeBinPath [ jail pkgs.opencode ]}
69+
70+ runHook postInstall
71+ '';
72+
73+ meta = with pkgs.lib; {
74+ description = "Run OpenCode in a sandboxed environment with optional session token";
75+ homepage = "https://kilimanjaro.io/vibe";
76+ license = licenses.mit;
77+ platforms = platforms.linux;
78+ };
79+ };
80+
81+ in {
82+ packages = {
83+ inherit jail vibe;
84+ default = vibe;
85+ };
86+
87+ devShells.default = pkgs.mkShell {
88+ name = "vibe-dev";
89+
90+ buildInputs = with pkgs; [
91+ opencode
92+ firejail
93+ git
94+ bash
95+ jq
96+ curl
97+ which
98+ ];
99+
100+ shellHook = ''
101+ echo "Vibe development shell"
102+ echo "Available tools: opencode, firejail, git, jq, curl"
103+ echo "Run 'jail' to start the sandbox wrapper"
104+ echo "Run 'vibe' to start OpenCode in sandbox (optional: vibe <token>)"
105+ '';
106+ };
107+ });
108+}
A
jail.sh
+101,
-0
1@@ -0,0 +1,101 @@
2+#!/usr/bin/env bash
3+
4+# opencode-sandbox - Run OpenCode in a sandboxed firejail environment
5+# This script runs in firejail with filesystem isolation
6+# while maintaining access to current directory and configuration
7+
8+set -euo pipefail
9+
10+# Enable OpenCode experimental support for oxfmt when listed as a package dependency
11+export OPENCODE_EXPERIMENTAL_OXFMT="true"
12+export EDITOR="echo"
13+
14+# Capture current environment
15+CURRENT_DIR="$(pwd)"
16+ROOT="$(git rev-parse --show-toplevel)"
17+
18+# For NixOS: resolve to actual Nix store paths (not symlinks)
19+OPENCODE_PATH="$(readlink -f "$(which opencode)")"
20+echo "Using $OPENCODE_PATH"
21+
22+# Build firejail command arguments
23+FIREJAIL_ARGS=(
24+ # Use noprofile to avoid default restrictions that might block large directories
25+ --noprofile
26+
27+ # Security restrictions
28+ --private-tmp # Private /tmp directory
29+ --noroot # Disable su/sudo inside sandbox
30+ --caps.drop=all # Drop all capabilities
31+ --nonewprivs # Prevent privilege escalation
32+ --nogroups # Don't inherit supplementary groups
33+
34+ # Filesystem access - whitelist specific paths only
35+ --whitelist="$ROOT"
36+ --read-only="$ROOT"
37+ --whitelist="$ROOT/.git" # if started in a subdirectory of a git project
38+ --read-write="$ROOT/.git" # => needs access to .git and .jj for bug and commits
39+ --whitelist="$ROOT/.jj"
40+ --read-write="$ROOT/.jj"
41+ --whitelist="$CURRENT_DIR" # Allow access to current directory
42+ --read-write="$CURRENT_DIR" # Make current directory writable
43+ --whitelist="/nix/store" # Make Nix tools available in dev shell
44+ --read-only="/nix/store"
45+ --whitelist="$HOME/.bashrc"
46+ --read-write="$HOME/.bashrc" # tool call aliases
47+ --whitelist="$HOME/.agents"
48+ --read-write="$HOME/.agents" # skills
49+ --whitelist="$HOME/.ssh" # to troubleshoot Nix depoyment
50+ --read-only="$HOME/.ssh"
51+)
52+
53+# Blacklist specific tools resident in /usr/bin environment that you absolutely don't want
54+# OpenCode using. This augments any restrictions you put in your OpenCode permissions.
55+BLACKLIST=(
56+ npm
57+ /usr/bin/npm
58+ yarn
59+ java
60+ perl
61+)
62+for bl in "${BLACKLIST[@]}"; do
63+ FIREJAIL_ARGS+=(--blacklist="$(which "$bl")")
64+done
65+
66+# Add configuration access if files/directories exist
67+if [ -d "$HOME/.config/opencode" ]; then
68+ FIREJAIL_ARGS+=(--whitelist="$HOME/.config/opencode")
69+ FIREJAIL_ARGS+=(--read-write="$HOME/.config/opencode")
70+
71+ # auth creds and logs
72+ FIREJAIL_ARGS+=(--whitelist="$HOME/.local/share/opencode")
73+ FIREJAIL_ARGS+=(--read-write="$HOME/.local/share/opencode")
74+fi
75+if [ -d "$HOME/.config/jj" ]; then
76+ FIREJAIL_ARGS+=(--whitelist="$HOME/.config/jj")
77+ FIREJAIL_ARGS+=(--read-only="$HOME/.config/jj")
78+fi
79+
80+# Add PNPM store
81+if [ -d "$HOME/.local/share/pnpm" ]; then
82+ FIREJAIL_ARGS+=(--whitelist="$HOME/.config/pnpm")
83+ FIREJAIL_ARGS+=(--read-only="$HOME/.config/pnpm")
84+ FIREJAIL_ARGS+=(--whitelist="$HOME/.local/share/pnpm")
85+ FIREJAIL_ARGS+=(--read-write="$HOME/.local/share/pnpm")
86+ FIREJAIL_ARGS+=(--whitelist="$HOME/.cache/node") # corepack installs
87+ FIREJAIL_ARGS+=(--read-only="$HOME/.cache/node")
88+
89+fi
90+
91+# add playwright browsers
92+if [ -d "$HOME/.cache/ms-playwright" ]; then
93+ FIREJAIL_ARGS+=(--whitelist="$HOME/.cache/ms-playwright")
94+ FIREJAIL_ARGS+=(--read-write="$HOME/.cache/ms-playwright")
95+fi
96+
97+# Network access (allow by default, can be restricted with --net=none)
98+# FIREJAIL_ARGS+=(--net=none) # Uncomment to disable network access
99+
100+echo "Starting in firejail sandbox..."
101+exec firejail "${FIREJAIL_ARGS[@]}" "$@"
102+
A
vibe.sh
+25,
-0
1@@ -0,0 +1,25 @@
2+#!/usr/bin/env bash
3+
4+# vibe - Run OpenCode in a sandboxed firejail environment
5+# Usage: vibe [<token>] or vibe -s <token>
6+
7+set -euo pipefail
8+
9+# Handle different argument patterns:
10+# - vibe (no args) -> jail opencode
11+# - vibe <token> -> jail opencode -s <token>
12+# - vibe -s <token> -> jail opencode -s <token>
13+
14+if [ $# -eq 0 ]; then
15+ # No arguments - run opencode without session token
16+ exec jail opencode
17+elif [ "$1" = "-s" ] && [ $# -eq 2 ]; then
18+ # Explicit -s flag with token
19+ exec jail opencode -s "$2"
20+elif [ $# -eq 1 ] && [ "$1" != "-s" ]; then
21+ # Single argument that is not -s, treat as token
22+ exec jail opencode -s "$1"
23+else
24+ echo "Usage: vibe [<token>] or vibe -s <token>" >&2
25+ exit 1
26+fi