Frappe Ops Deployment
Impertio-Studio/Frappe_Claude_Skill_Package
A skill your agent uses when deploying Frappe/ERPNext to production, configuring Nginx or Supervisor, setting up Docker, enabling SSL, or hardening security.
Work out why the blot-container-{blue,green,yellow} Docker containers from the most recent production deployment have restarted — distinguishing a normal deploy-triggered restart from a crash (V8…
$ npx skills add blotcms/blot --skill investigate-production-container-restarts -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install blotcms/blot investigate-production-container-restarts --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/blotcms/blot.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/investigate-production-container-restarts .claude/skills/investigate-production-container-restarts && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "investigate-production-container-restarts" agent skill from https://github.com/blotcms/blot/tree/master/.claude/skills/investigate-production-container-restarts into .claude/skills/investigate-production-container-restarts/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "investigate-production-container-restarts", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/blotcms/blot/tree/master/.claude/skills/investigate-production-container-restartsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add blotcms/blot --skill investigate-production-container-restarts -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install blotcms/blot investigate-production-container-restarts --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/blotcms/blot.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/investigate-production-container-restarts .agents/skills/investigate-production-container-restarts && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "investigate-production-container-restarts" agent skill from https://github.com/blotcms/blot/tree/master/.claude/skills/investigate-production-container-restarts into .agents/skills/investigate-production-container-restarts/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "investigate-production-container-restarts", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add blotcms/blot --skill investigate-production-container-restarts -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install blotcms/blot investigate-production-container-restarts --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/blotcms/blot.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/investigate-production-container-restarts .cursor/skills/investigate-production-container-restarts && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "investigate-production-container-restarts" agent skill from https://github.com/blotcms/blot/tree/master/.claude/skills/investigate-production-container-restarts into .cursor/skills/investigate-production-container-restarts/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "investigate-production-container-restarts", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/blotcms/blot.git --path .claude/skills/investigate-production-container-restarts--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add blotcms/blot --skill investigate-production-container-restarts -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install blotcms/blot investigate-production-container-restarts --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/blotcms/blot.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/investigate-production-container-restarts .gemini/skills/investigate-production-container-restarts && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "investigate-production-container-restarts" agent skill from https://github.com/blotcms/blot/tree/master/.claude/skills/investigate-production-container-restarts into .gemini/skills/investigate-production-container-restarts/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "investigate-production-container-restarts", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install blotcms/blot investigate-production-container-restartsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add blotcms/blot --skill investigate-production-container-restarts -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/blotcms/blot.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/investigate-production-container-restarts .github/skills/investigate-production-container-restarts && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "investigate-production-container-restarts" agent skill from https://github.com/blotcms/blot/tree/master/.claude/skills/investigate-production-container-restarts into .github/skills/investigate-production-container-restarts/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "investigate-production-container-restarts", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add blotcms/blot --skill investigate-production-container-restarts -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install blotcms/blot investigate-production-container-restarts --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/blotcms/blot.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/investigate-production-container-restarts .opencode/skills/investigate-production-container-restarts && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "investigate-production-container-restarts" agent skill from https://github.com/blotcms/blot/tree/master/.claude/skills/investigate-production-container-restarts into .opencode/skills/investigate-production-container-restarts/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "investigate-production-container-restarts", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
investigate-production-container-restartsWork out why the blot-container-{blue,green,yellow} Docker containers from the most recent production deployment have restarted — distinguishing a normal deploy-triggered restart from a crash (V8…
Investigate Production Container Restarts is an agent skill from blotcms/blot. Work out why the blot-container-{blue,green,yellow} Docker containers from the most recent production deployment have restarted — distinguishing a normal deploy-triggered restart from a crash (V8 heap OOM, Linux cgroup OOM kill, a lost sync folder lock - [LOCK COMPROMISED] - from a stalled Redis connection, or the deploy script's own health-check rollback). Use when asked to investigate container restarts, figure out why a container went down, or check on the health of the latest deploy.
Its SKILL.md is about 5.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in DevOps & Cloud, covering Deployment and Containers. It works with Docker, Linux and Redis. The repository describes itself as: Turns a folder into a website. The licence is AGPL-3.0.
8 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 6250431. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
sshdockernpmgitghnodecurlFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use ssh, docker, npm, git, gh and curl, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Investigate Production Container Restarts loads about 5.2k tokens when it runs. Until then it costs about 134 tokens; SKILL.md has 2,598 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from blotcms/blot at commit 6250431, republished under its AGPL-3.0 licence (© blotcms). 2,598 words, ~5,151 tokens.
.claude/skills/investigate-production-container-restarts/SKILL.md (or your agent's skills folder).Blot runs three named app containers plus an airlock sidecar (see
scripts/deploy/constants.js):
blot-container-blue (port 8088, siteConfig) — failover, sites+blogsblot-container-green (port 8089, siteConfig) — dashboard/brochure/syncblot-container-yellow (port 8090, blogsConfig) — preview+published blogsblot-airlock — separate egress sidecar, not part of blue/green/yellowEvery container runs docker create --restart unless-stopped, so Docker
itself will silently restart a crashed container — a restart is not
inherently a deploy problem, but it's also not nothing. This skill works
out which of three things happened:
Confirm with the user before running anything against production
that isn't on the auto-approved list below, and stick to read-only
commands (log tailing, docker inspect, docker logs, read-only
redis-cli) unless a state-changing action has been explicitly
authorized.
Auto-approved (no confirmation needed) — these read-only commands
over ssh blot may be run without asking:
docker ps -a and docker inspect on blot-container-{blue,green,yellow}
(release ID, CreatedAt, RestartCount, OOMKilled, exit code)cat ~/docker-health-check.logdmesg | grep -i kill (or the kills helper)docker logs <container> with --since/--until, including grepping
for FATAL ERROR / JavaScript heap out of memorygrep <request-id> /var/instance-ssd/logs/access.log (or the req
helper) to find the triggering requestAnything else (state-changing commands, restarts, deploys) still needs explicit user approval.
SSH host is blot. Each container is created with
-e BLOT_RELEASE_ID=<commitHash> (scripts/deploy/util/generateDockerCommand.js)
and named ${REGISTRY_URL}:${commitHash} as its image tag — this is the
ground truth for "what deploy is currently running," independent of
docker ps's uptime column:
ssh blot "docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.CreatedAt}}\t{{.Image}}'"
ssh blot "for c in blot-container-blue blot-container-green blot-container-yellow; do echo \$c:; docker inspect \$c --format '{{range .Config.Env}}{{println .}}{{end}}' | grep BLOT_RELEASE_ID; done"Cross-reference the commit hash against GitHub to see what actually shipped and when:
git log -1 <commit-hash>
gh run list --workflow=deploy.yml --limit 5If all three containers share the same BLOT_RELEASE_ID and a similar
CreatedAt, that confirms they were replaced together by one deploy run —
the baseline for "expected" restarts. A container with a different
(older) BLOT_RELEASE_ID than its siblings, or a much older CreatedAt,
means it didn't pick up the latest deploy — that's itself worth explaining
(failed health check → rollback left it on the old image; see step 4).
docker ps -a — is this actually a restart worth investigating?ssh blot "docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.CreatedAt}}'"Up <a few minutes> with a CreatedAt matching the deploy time = the
container was recreated by the deploy itself (docker create + docker start, per container, once). Normal, expected, not a crash.Up <a few minutes> with a CreatedAt from before the deploy = the
same container object restarted (not recreated) after the deploy
finished — this is Docker's --restart unless-stopped kicking in after
a crash, not part of the deploy process. This is the case worth digging
into.RestartCount > 0 confirms Docker has restarted this container object at
least once since it was created:ssh blot "docker inspect <container> --format 'OOMKilled={{.State.OOMKilled}} ExitCode={{.State.ExitCode}} StartedAt={{.State.StartedAt}} RestartCount={{.RestartCount}}'"OOMKilled only reflects a Docker/cgroup-level OOM kill of the whole
container — it's usually false even when the Node process inside hit
its own --max-old-space-size limit and crashed on its own. Don't treat
OOMKilled=false as ruling out memory as the cause; check both failure
modes in step 3 regardless.
Also check the auto-restart health-check script's own log, which is a
separate mechanism from Docker's --restart policy — it appends a line
every time it force-restarts a container it decided was unhealthy:
ssh blot "cat ~/docker-health-check.log"Several distinct causes look identical in docker ps but require
different evidence and point to different fixes. Check each — don't stop
at the first one that seems plausible. Grep the end of the previous run's
log for FATAL ERROR, LOCK COMPROMISED and Unhandled 'error' event
before anything else; between them they cover most crashes.
ssh blot "docker logs <container> --since <before-crash> --until <after-crash> 2>&1 | grep -B5 'FATAL ERROR\|JavaScript heap out of memory'"Each fatal error also leaves a Node report (JS stack at the crash, heap
spaces, resource usage; env vars excluded) in
/var/www/blot/data/node-reports/<container>/report.*.json on the host.
These outlive log rotation and container recreation, so check them first
(ls/cat there is read-only):
ssh blot "ls -lt /var/www/blot/data/node-reports/<container>/ | head"If the container's logs have rotated past the crash, openresty still has
it: the error log shows a burst of connect() failed / prematurely closed errors to the container's port in the crash second, and the
access log shows the in-flight requests that died with it (502, long
request time, up=127.0.0.1:<port>):
ssh blot "zcat -f /var/instance-ssd/logs/error.log* | grep ':8090' | grep -c 'connect() failed'"The crash timestamp is the Starting server on ... line that follows the
restart in the container's log (search forward from there to find where
the previous run's log ends). Almost always an application-code problem
— something holding too much data in memory for a single request — not a
memory-limit tuning issue on its own. Read the log lines immediately
before the crash to find the triggering request (step 5).
ssh blot "dmesg | grep -i kill"
# or the bashrc helper, which converts dmesg's boot-relative timestamps to human-readable and filters for OOM events:
ssh blot "kills"Confirm the killed process was actually node (not esbuild, chromium, or
something unrelated sharing the container), and compare its anon-rss at
kill time against the container's configured memory limit:
ssh blot "docker inspect <container> --format '{{.HostConfig.Memory}}'"[LOCK COMPROMISED], ECOMPROMISED)A sync holds a per-blog folder lock in Redis (app/sync/lock.js): 10s TTL,
renewed by a heartbeat EXTEND every 3s over the shared node-redis
connection. If a renewal doesn't reach Redis before the TTL lapses, the
lock is lost, and app/sync/index.js deliberately rethrows so the process
stops writing. It mostly hits green (which runs the syncs).
Signature:
[LOCK COMPROMISED] {...} diagnostics
blocks, then Error: Lock was lost: blog:<id>:folder-lock thrown from
app/sync/index.js with code: 'ECOMPROMISED';OOMKilled=false, and no Node report (it isn't a fatal V8 error);ssh blot "docker logs <container> --since <before> --until <after> 2>&1 | grep -n 'LOCK COMPROMISED\|Lock was lost\|\[LOCK\]'"Read the heartbeat instrumentation:
[LOCK] slow heartbeat <key> tickDelay=… roundTrip=… is logged for
any renewal over 500ms.tickDelay near 0 means the timer fired on time, so the event loop
isn't to blame.roundTrip means the EXTEND sat on the connection.[LOCK] stall probe … probePing=… idle=… qbuf=… omem=… comes from a
separate Redis connection, taken while a heartbeat is outstanding.probePing means Redis itself is responsive.qbuf/omem on the shared connection means nothing is backed
up inside Redis either.elu= on request lines is event loop utilisation over that
request's lifetime./health request that took several seconds with elu=0.02 proves
the process sat idle, waiting on I/O.elu=1.00 on a 1ms request means nothing.slow heartbeat lines per container since the
deploy. A healthy connection logs few or none.Then check the Redis host. That's where the root cause has been, and
it is a separate production host (ssh redis), so confirm with the user
first:
ssh -n redis 'grep TCP: /proc/net/sockstat; cat /proc/sys/net/ipv4/tcp_mem; nstat -az TcpExtTCPMemoryPressures TcpExtTCPMemoryPressuresChrono TcpExtPruneCalled TcpExtTCPRcvQDrop TcpExtTCPOFODrop'
ssh -n redis 'tail -20 ~/tcpmem.log' # 5-minute history, from /etc/cron.d/blot-redis (config/redis/bin/tcpmem-log.sh)sockstat's mem and tcp_mem are both in pages. Once mem is above
tcp_mem[1], the kernel is in memory-pressure mode. Above tcp_mem[2],
each socket may buffer only a minimal amount of incoming data.TCPMemoryPressures counts entries into pressure since boot.TCPMemoryPressuresChrono is the total time spent in it, in ms. It is
only added to when the kernel leaves pressure, so a value that jumps
dates the episode.From 25 Sep to 6 Oct 2026 the Redis host's kernel TCP memory accounting
had leaked past tcp_mem[2], with near-empty real socket buffers.
net.ipv4.tcp_mem above the leaked count (runtime sysctl -w)
cleared it at once.To confirm a stall is on the network path, and not in the app:
PING\r\n into one fresh TCP
connection to Redis, and time the replies. The Redis address is
BLOT_REDIS_HOST in a container's env; send the script over stdin as
ssh blot 'script=$(cat); node -e "$script"' < burst.js.blotnet, e.g. docker run --rm -i --network blotnet --entrypoint node <a live container's image> -.RetransSegs in /proc/net/snmp before and after.ethtool -S eth0 | grep allowance counters too;
they rule the AWS network allowance on this side in or out.npm run fix-probe -- <blog> (scripts/fix-probe/README.md) runs
a sync/fix check (default tag-ghosts) read-only in a throwaway
container./proc/net/tcp) state, and retransmits.Don't respond to this by loosening the lock (a longer TTL, swallowing
ECOMPROMISED). The crash is the alarm, and loosening it hides a
Redis-wide problem: every container's large reads and writes are slowed
too.
Pitfalls when gathering this evidence:
ssh -n (or redirect stdin) for remote commands that might read
standard input. A grep whose file variable came out empty, or a
backgrounded node -, will otherwise hang or silently do nothing.docker run <image tag> pulls the image if the tag isn't on the host
under that name, even when the containers are running it.The log ends with throw er; // Unhandled 'error' event and the name of
the object that emitted it. There is no Node report, OOMKilled=false, and
no LOCK COMPROMISED. The emitter names the culprit; look for an in-flight
request on that container in the same second (step 5), usually a 502 in the
access log with a long request time.
Example (green, 9 Oct 2026): Error: aborted (ECONNRESET) emitted "on
Service instance", during a ~580 MB git push. Pushover wraps each git
request in an http-duplex Service that re-emits the request's errors, and
only some of those objects had a listener. Fixed by
app/clients/git/guardServices.js (#2086), which gives every one a listener
and stops its git process.
For the git client, also check:
every git child now logs one line when it exits:
Git: receive-pack|upload-pack <handle> exit=… duration=… rx=… tx=… [stderr=…]. A push that was cut off shows a non-zero exit, a signal or
git's own error.
stuck git processes (before #2086 an aborted push left git-receive-pack
and git index-pack waiting forever, each index-pack holding hundreds of
MB inside the container's memory limit):
ssh -n blot "docker exec blot-container-green sh -c 'ps -o pid,etime,rss,args | grep [g]it-'"leftover push staging directories (objects/tmp_objdir-incoming-* in the
bare repos). A push killed by a crash or deploy can't clean up after
itself; app/clients/git/sweepQuarantine.js removes ones older than 24h
daily at 05:00 on green. Several similar-sized directories in one repo
mean a user retried a large push that kept failing:
ssh -n blot "docker exec blot-container-green sh -c 'find /usr/src/app/data/git -mindepth 3 -maxdepth 3 -type d -name \"tmp_objdir-incoming-*\" -exec du -sh {} +'"scripts/deploy/util/checkHealth.js polls
docker inspect --format='{{.State.Health.Status}}' and then
curl --fail http://localhost:<port>/health after each container starts,
with a 3-minute timeout. If this fails, the deploy script's rollback logic
removes/replaces the container rather than leaving a crashed one running —
so a container stuck on an older BLOT_RELEASE_ID than its siblings
(step 1) is the signature of this path, not a crash at all. Check
/var/log/deploy-commands.log for the deploy run's own output around that
time, and the corresponding GitHub Actions run (gh run view <id> --log)
for which health check attempt failed and why.
Attaching the airlock network to an already-running container reprograms
its routing table and drops in-flight conntrack entries, which used to
crash-restart every container exactly once per deploy with an unhandled
read ETIMEDOUT talking to the off-box Redis instance. Fixed by
docker create (stopped) → docker network connect → docker start, so
this shouldn't recur — but if you see a single ETIMEDOUT-flavored crash
on every container within seconds of a deploy, this is the pattern to rule
out first before assuming a new regression.
Blue/green/yellow each run a single Node process serving many sites or
blogs — a slow/blocking render for one site can stall or crash the whole
container, not just that one request (root cause of issue #1806, nashp.com's
uncached /archives and /tagged/<slug> pages blocking the event loop; see
the node-response-time-review skill for identifying which site is
responsible if the crash correlates with heavy traffic to one domain rather
than a memory leak across many).
ssh blot "docker logs <container> --since <before-crash> --until <crash-time>"gives the log lines right before the crash. Cross-reference the last live request ID(s) (the 32-char hex string on every log line) against the openresty access log for the full URL, status, and timing:
ssh blot "grep <request-id> /var/instance-ssd/logs/access.log"Or use the req <pattern> bashrc helper, which greps access/error logs and
all three containers' logs in one shot.
Once a candidate request is identified, npm run render-probe -- <url>
(see scripts/render-probe/README.md) renders it in a one-off container of
the same image, data (read-only) and env, with heap, event loop, GC,
Redis and per-render-step timings recorded, and optionally a heap snapshot
near the heap limit. It can't take down the live containers. It runs
against production, so confirm with the user before each run. Useful
runs:
--stats <url>: entry count, catalog size and backlink weight, with no
rendering. Is this blog unusual?<url> --concurrency N: does memory scale with concurrent cold renders?--replay <access log> --from … --to …: the real traffic leading up to
a crash (rotated .gz logs work too).--release <older commit>: does an older release render the same page
fine? That bisects a regression.For a crash during sync work rather than a render, npm run fix-probe
does the same for a sync/fix check, and npm run build-probe does it for
rebuilding a post. See the lost-folder-lock section in step 3.
Prefer reproducing locally over experimenting on production once a
candidate site/request is identified: clone of a real large blog through
the normal dev stack (npm start / docker-compose), toxiproxy to
simulate realistic server↔redis latency, and ab (ApacheBench) for
concurrent load. A large, growing gap between ab's wall-clock mean and
the server's own per-request logged timings under concurrency signals
requests queueing behind event-loop-blocking work rather than running in
parallel — the same signature as the process eventually exhausting memory
under sustained load.
This skill only identifies why the restart happened — it doesn't fix
the underlying app bug unless separately asked to. If the cause is a
genuine app-level issue (heap growth on a specific render path, a specific
site's pathological page), file or update a GitHub issue with: which
container(s), how many restarts, the failure mode (V8 OOM / cgroup OOM /
lost folder lock / health-check rollback), the triggering request(s) if found, and whether it
correlates with a specific site (cross-check against
node-response-time-review if so). If the cause is deploy tooling itself
(a bad health check, a rollback that left a stale container running),
that's a scripts/deploy/ issue, not an app-code one — say so explicitly
so it doesn't get miscategorized. Likewise, a lost folder lock traced to
the Redis host or the network path is an infrastructure issue (update
blotcms/blot#2041 or open a new one), not an app-code one.
© blotcms, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/investigate-production-container-restarts of blotcms/blot.
Open the folder on GitHubat commit 6250431
Investigate Production Container Restarts next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Investigate Production Container Restarts this skillblotcms/blot | 2k | — | ~5.2k | Automated safety check: Pass | AGPL-3.0 | |
| Frappe Ops DeploymentImpertio-Studio/Frappe_Claude_Skill_Package | 189 | — | ~2.4k | Automated safety check: Notes | MIT | |
| Self-Hosted n8n Deploymentczlonkowski/n8n-skills | 6.4k | — | ~3.5k | Automated safety check: Notes | MIT | |
| Setup Workshopbrevdev/workshop-build-an-agent | 146 | — | ~2.3k | Automated safety check: Notes | Apache-2.0 | |
| Docker Deploymentfossasia/eventyay | 1.7k | — | ~574 | Automated safety check: Notes | Apache-2.0 | |
| Supercheck Infrastructure Deploymentsupercheck-io/supercheck | 215 | — | ~1.4k | Automated safety check: Notes | AGPL-3.0 |
Impertio-Studio/Frappe_Claude_Skill_Package
A skill your agent uses when deploying Frappe/ERPNext to production, configuring Nginx or Supervisor, setting up Docker, enabling SSL, or hardening security.
czlonkowski/n8n-skills
Deploys a production n8n instance to a fresh Linux server over SSH with Docker Compose and Caddy HTTPS, in single or queue mode, and covers updates, backups and hardening.
brevdev/workshop-build-an-agent
This skill should be used when the user wants to set up, install, deploy, bootstrap, or "spin up" the Build-an-Agent workshop (a.k.a.
fossasia/eventyay
Docker Compose, container services, deployment. An agent skill from fossasia/eventyay.
supercheck-io/supercheck
Work on Supercheck Docker Compose, K3s, Kubernetes manifests, gVisor, OpenTofu/Hetzner, secrets, external services, autoscaling, backups, disaster recovery, DNS/TLS, or production deployment.
magnus919/agent-skills
Deploy, configure, and maintain a self-hosted Headscale control server on Linux or Docker.
blotcms/blot
Grow or shrink the EBS volume that holds the app host's data directory (/var/www/blot/data), with config/host/data-volume/resize.sh (grow in place; shrink by live rsync passes, a brief read-only…
blotcms/blot
Review what Blot's request-time folder-link rewrite (app/blog/render/replaceFolderLinks) still does in production, from the [folder-links] and [folder-asset-origin] log lines, to decide what has to…
blotcms/blot
Investigate a "Dropbox sync issue" alert email from Blot's hourly Dropbox sync validation (each flagged blog lists unsynced changes, Fix() repairs, errors and/or a stuck folder lock; the changes…
blotcms/blot
Scan the production openresty access log (/var/instance-ssd/logs/access.log) for requests with slow upstream response times (st=, the time the node containers took to answer), triage and rank them…
blotcms/blot
Investigate an "iCloud resync found changes" admin email (the ICLOUDRESYNCISSUE email a macserver-requested resync sends when it found changes, Fix() repairs or errors, with the macserver's reason)…
blotcms/blot
Analyze production Node.js app container response times to find slow-rendering sites, cross-checking against nginx queuing delay to rule out false positives (a site only looks slow because the event…
Categories
Work out why the blot-container-{blue,green,yellow} Docker containers from the most recent production deployment have restarted — distinguishing a normal deploy-triggered restart from a crash (V8…. Investigate Production Container Restarts is an agent skill from blotcms/blot. Work out why the blot-container-{blue,green,yellow} Docker containers from the most recent production deployment have restarted — distinguishing a normal deploy-triggered restart from a crash (V8 heap OOM, Linux cgroup OOM kill, a lost sync folder lock - [LOCK COMPROMISED] - from a stalled Redis connection, or the deploy script's own health-check rollback).
Investigate Production Container Restarts fits situations like: asked to investigate container restarts; figure out why a container went down; check on the health of the latest deploy.
Run `npx skills add blotcms/blot --skill investigate-production-container-restarts -a claude-code`. Or copy the skill folder (.claude/skills/investigate-production-container-restarts in blotcms/blot) into .claude/skills/investigate-production-container-restarts in your project. Claude Code loads it when a task matches its description.
Run `npx skills add blotcms/blot --skill investigate-production-container-restarts -a codex`. Or copy the skill folder (.claude/skills/investigate-production-container-restarts in blotcms/blot) into .agents/skills/investigate-production-container-restarts in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add blotcms/blot --skill investigate-production-container-restarts -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/investigate-production-container-restarts, .gemini/skills/investigate-production-container-restarts, .github/skills/investigate-production-container-restarts and .opencode/skills/investigate-production-container-restarts in your project.
Going by SKILL.md and its folder, Investigate Production Container Restarts needs the command-line tools its instructions call (ssh, docker, npm, git, gh and node). Our summary lists: Docker.
SKILL.md contains no URLs. Its commands use ssh, docker, npm, git, gh and curl, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Investigate Production Container Restarts is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.2k tokens (SKILL.md is roughly 21k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Investigate Production Container Restarts: Frappe Ops Deployment (Impertio-Studio/Frappe_Claude_Skill_Package, 189 stars), Self-Hosted n8n Deployment (czlonkowski/n8n-skills, 6.4k stars), Setup Workshop (brevdev/workshop-build-an-agent, 146 stars) and Docker Deployment (fossasia/eventyay, 1.7k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
blotcms (a GitHub organization) maintains it in blotcms/blot, which has 1,983 GitHub stars. The repository holds 10 skills in this directory. The repository was last updated on October 10, 2026.
Source: blotcms/blot on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.