Install
$ agentstack add skill-therocksss-vpn-egress-vpn-egress-orchestrator ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
VPN Egress Orchestrator
Running many reachability tasks in parallel over one shared container. The stack tolerates this — it was configured for it — but only under a specific contract. Break the contract and agents kill each other's runs.
First: do you actually need subagents?
check-url.js takes any number of URLs in one invocation, sharing one browser. Twenty URLs in one call is faster than twenty subagents, uses no extra context, and produces one already-merged result.
MSYS_NO_PATHCONV=1 docker exec playwright-vpn \
node /scripts/check-url.js url1 url2 url3 … url20
Fan out only when each target needs real per-target work — reading a config to explain why one failed, cross-referencing a Caddyfile, chasing a redirect chain, judging whether a page rendered correctly. That's reasoning work, which parallelizes. Navigation alone does not.
If the task is "check these N URLs", stop here and use vpn-egress-testing.
The contract
1. The parent owns the stack. Always.
Subagents never run docker compose, tools/stack.sh up, or tools/stack.sh stop.
Parallel agents managing one shared stack race: two up calls collide, and a stop from the first agent to finish kills every run still in flight — producing timeouts that look exactly like unreachable sites.
Before dispatching anything:
cd projects/vpn-egress && bash tools/stack.sh up
MSYS_NO_PATHCONV=1 docker exec playwright-vpn node /scripts/check-ip.js
Both must pass. check-ip.js reporting ok: false means every result you are about to collect is worthless — fix it first (vpn-egress-setup).
Each shard also verifies the tunnel for itself before touching a URL, so an off-tunnel fan-out produces refusals rather than a batch of confident wrong answers. Checking here first is still worth it: it fails once, up front, instead of N times across N dispatched agents.
Do not run tools/exit.sh while a sweep is in flight. Changing the exit city recreates gluetun, which destroys the network namespace every shard is using — same class of damage as docker compose stop, and the half of the results taken before the switch came from a different country than the half after. Pick the exit city before dispatching.
2. Dispatch literal commands, not skill names
Put the exact command in each subagent's prompt, along with what pass and fail look like. Never "use the vpn-egress-testing skill" — subagents may have no Skill access, and one re-deriving commands will invent a variant that breaks the contract.
docker exec is available to any agent with Bash, which is why this works at all.
3. Group output under one RUN_ID
Set a shared RUN_ID so every subagent's output lands under one directory and you can find it all afterwards:
MSYS_NO_PATHCONV=1 docker exec -e RUN_ID=sweep-2026-07-30 playwright-vpn \
node /scripts/check-url.js --label=shard-1 https://a.example
Without it, each invocation gets its own timestamp+pid directory — still collision-free, just scattered.
4. Respect the concurrency ceiling
Four concurrent runs is verified good. All subagents docker exec into the same playwright-vpn container, each launching its own Chromium against one shared /dev/shm (1GB).
Beyond four, shard the work rather than raising the fan-out — give each of four agents more targets. Exceeding the shm budget produces timeouts, which are indistinguishable from unreachable sites, so the failure quietly corrupts your results instead of announcing itself.
Dispatch template
Give each subagent something self-contained:
> Check these URLs from an external vantage point and diagnose each failure. > > Run exactly this, from projects/vpn-egress: > > ``bash > MSYS_NO_PATHCONV=1 docker exec -e RUN_ID= playwright-vpn \ > node /scripts/check-url.js --label= --timeout=20000 > ` > > stdout is a JSON envelope; stderr is progress. ok: true needs status > - errorKind: "timeout" — nothing came back. > - errorKind: "refused" — actively rejected; port or backend problem. > - errorKind: "dns" — name doesn't resolve. > - status 200 but tls.issuer is Caddy Local Authority — reachable but no > real browser will trust it; ACME issuance never completed. Report this as > a failure, not a pass. > > Read the exit code before interpreting anything: > - 0 — checked, at least one URL was reachable. > - 1 — checked, everything failed. A real result about the URLs. > - 2 — **no answer was obtained.** Either a usage error, or the tunnel > gate refused to run (blocked: true, total: 0 in the envelope). > Report that you could not test. Never report these URLs as down. > > Do NOT run docker compose, tools/stack.sh, or tools/exit.sh — the > stack is already running and managed by the parent. Do NOT write your own > check script. Do NOT add --allow-off-tunnel` to make a refusal go away; > it disables the guarantee that results came from outside the network. > > For each failing URL, investigate the cause and report it. Return the raw > JSON envelope plus your per-URL diagnosis.
Substitute `, , and ` before dispatching. The subagent should never have to fill in a blank.
Merging results
A subagent's final report is not shown to the user — relay what matters yourself.
- Parse each returned envelope. Every result has the same shape, so they
concatenate directly.
- Check
blockedon every envelope first. A shard withblocked: true
tested nothing. Its URLs are unanswered, not down — fold them into the gap list in step 3, never into the failure list.
- Reconcile against the input list. **Name every URL no agent conclusively
answered** — an agent that crashed, timed out, or was blocked leaves a gap, and a gap silently dropped reads as a pass.
- Confirm every shard came from the same exit. Compare
tunnel.ipand
tunnel.server across envelopes. If they differ, the tunnel moved mid-sweep and the results are not one comparable set — say so rather than merging them silently.
- Report per-URL: status,
errorKind, andtls.issuerwhere it matters. - Separate reachable from correct. A 200 with an untrusted cert is a
failure users will experience, and it is the most-missed one here.
- State the vantage point in the summary — exit city and country from
tunnel. A reachability claim without it can't be interpreted later.
Screenshots and JSON are under scripts/out//. Read them if a diagnosis needs evidence, then delete — they're disposable and gitignored.
Known bug — evidence can be overwritten when shards share a RUN_ID. Screenshot filenames are de-duplicated per process, not per run directory, so if the same host appears in two shards, the second overwrites the first's screenshot with no error. The JSON results are unaffected. Until it's fixed, shard by host (never split one host across shards) if screenshots matter.
Teardown
Only after all delegated work is done:
cd projects/vpn-egress && bash tools/stack.sh stop
Use the tool, not a raw docker compose stop. The containers may be owned by a larger compose project that includes this repo's file, in which case a plain docker compose stop run from this directory matches nothing and silently succeeds without stopping anything. tools/stack.sh resolves the owning project first.
stop, not down — keeps volumes and the Playwright install. Leave it running if the user also wants the GUI browser.
Stopping while any subagent is still working produces timeouts that look like site failures. Confirm every agent has reported before tearing down.
Failure modes specific to fan-out
| Symptom | Cause | | --- | --- | | Several shards time out together, others fine | Concurrency ceiling exceeded — /dev/shm exhausted. Re-run the failed shard alone before believing it. | | All shards fail at once, mid-run | Someone ran docker compose stop or tools/exit.sh, or the tunnel dropped. Check tools/stack.sh health and re-run. | | Shards return blocked: true and exit 2 | The tunnel gate refused — egress wasn't confirmed. Nothing was tested. Fix the tunnel, then re-run; do not report those URLs as down. | | Shards disagree on tunnel.ip | The exit moved mid-sweep. The results describe two different vantage points and must not be merged as one set. | | A shard reports MODULE_NOT_FOUND on a Windows path | Its command lost MSYS_NO_PATHCONV=1. A dispatch-template bug, not a network result. | | Screenshots missing or overwritten | A subagent wrote its own script with a fixed output path. They shouldn't be writing scripts. | | Results contradict a known-good domain | Verify the browser is on the tunnel (check-ip.js) before trusting any of the batch. |
Related
vpn-egress-testing— one URL, or several in one call. The common case.vpn-egress-setup— stack won't start.projects/vpn-egress/docs/ARCHITECTURE.md— why one container is shared and
what that constrains.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: THEROCKSSS
- Source: THEROCKSSS/vpn-egress
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.