So ive been looking into claude code CLI for unraid and found this discussion. Sounds like there is a few community built versions but they may still need some work to be mature enough to be trusted as a CA plugin for the wider community. Im by no means a coder or developer and have limited expeience in this area. I did how ever take all the info here and from the unoffical plugin doc and put this into this into Claude chat to discuss how to address some of the issues and concerns rasied, potentially creating a more suitable plugin design. I may consider testing this on my own server using claude code to help me build it, but im no where near experienced enough to actually review the AI generated code and then feel confident sharing this with the wider community as trusted and tested. Maybe someone who has more experience could pick this up and built it with claude and review? I asked Claude to draft a design document to share in this forum post. Remember this is 100% AI generated so DYOR if you plan to use this info. Claude Code for Unraid — Proposed Plugin Design Background and motivationSeveral community members have already built working implementations of Claude Code for Unraid — as a native plugin and as a Docker Compose stack — and the effort and enthusiasm behind these is genuinely appreciated. This design proposal builds directly on that work, incorporates the structural feedback raised in this thread by a community developer, and aims to describe what a plugin submission suitable for Community Applications would look like. The goal is not to criticise what has already been built. AI-assisted plugin development is a genuinely new workflow and the conventions are hard to discover — the information is scattered across a decade of forum posts with no official developer guide. The recently created plugin documentation at https://plugin-docs.mstrhakr.com is the best consolidated reference currently available and this design follows it throughout. Why a plugin rather than a Docker containerThis question was raised directly in the thread and is worth addressing properly. The standard CA guidance is correct that Docker is preferred for isolated applications, but Claude Code is a genuine exception. Its primary value on Unraid is managing the host system itself — diagnosing array issues, editing config files, writing scripts, working with Docker and VM configurations. If the array is stopped or Docker is disabled, a containerised Claude Code cannot help with the very situations where you need it most. The Docker Compose approach is a reasonable workaround for getting Claude Code running quickly, but it requires the array and Docker to be running, limits Claude's access to only the volumes explicitly mounted in the compose file, and adds orchestration overhead for what is fundamentally a CLI tool. For server management use, host-level installation is the right architectural choice. That said, the compose approach has real merit for users who specifically want to sandbox Claude's filesystem access to defined directories. Both approaches solve different problems and both have a place in the community. What the current implementations get rightThe existing native plugin implementations successfully handle the core requirement: getting the Claude Code binary installed and accessible from the Unraid terminal, with authentication and settings persisted to appdata. The appdata auto-detection from Docker config is a useful feature worth keeping. The settings page placement under Settings > Utilities follows the right conventions. The community has also correctly identified and documented a critical operational concern: Claude Code running as root has unrestricted ability to execute any command on the system. This is documented honestly in the twispers fork and should be a prominent and persistent part of any official plugin's disclosure — not buried, not dismissible. What needs to change for CA inclusionThe structural feedback raised in this thread by an experienced community developer identified four specific issues. Each has a concrete fix in this design. Issue 1: No Slackware package (.txz)The existing implementations download files and cache them on flash directly, without wrapping them in a versioned Slackware package. This works for initial installation but breaks the update mechanism — when a new version of the plugin scripts is released, existing installs have no way to receive the updated files short of uninstalling and reinstalling. The fix is a proper .txz package containing all runtime files. This is what upgradepkg extracts into RAM on every boot, and it is how every mature Unraid plugin handles file delivery and updates. Issue 2: No checksums on downloaded filesFiles referenced in the .plg must have <SHA256> tags. Without them there is no integrity verification — the plugin installs whatever is at the URL, even if the file has changed or been corrupted. For a tool running as root with full filesystem access this is a meaningful risk, not a theoretical one. Issue 3: The array timing race conditionThe existing plugin uses a background wait loop — up to five minutes — to detect when the array has started before setting up the appdata symlink. This has two failure modes: it can write to /mnt/user before the array has actually mounted (creating stale paths that confuse subsequent array operations), and it will fail entirely if the array takes longer than the wait period. This is the most technically subtle issue and the one most likely to produce hard-to-diagnose symptoms. The fix is Unraid's event system. The plugin registers event handler scripts that emhttp calls at precise points in the array lifecycle. No polling, no race conditions, no arbitrary timeouts. Issue 4: No path to receive security updates for the binaryThe current implementations cache a specific version of the Claude Code binary at install time with no mechanism to update it short of reinstalling the plugin. This matters because three CVEs were disclosed in Claude Code in early 2026: two allowed arbitrary command execution from malicious project configuration files (CVE-2025-59356, CVE-2025-59536), and one allowed API key theft (CVE-2026-21852, patched in v2.0.65). A plugin running as root on a NAS needs a clear path to receive these patches without requiring a full reinstall. Corrected plugin structureA CA-quality plugin has three layers. The .plg file is the installer. The .txz Slackware package contains all runtime files and is extracted into RAM on every boot. User configuration lives permanently on the USB flash drive. ┌──────────────────────────────────────────────────────────────┐
│ GitHub Releases │
│ │
│ claude-code.plg ─────────────────► claude-code-2026.04.07.txz
│ (plugin installer) references (SHA256 verified) │
└──────────────────────────────────────────────────────────────┘
│ plugin install
▼
┌──────────────────────────────────────────────────────────────┐
│ USB Flash /boot (survives all reboots unconditionally) │
│ │
│ /boot/config/plugins/claude-code.plg │
│ /boot/config/plugins/claude-code/ │
│ ├── claude-code.cfg ← user settings (key=value) │
│ └── claude-code-2026.04.07.txz ← cached package │
└──────────────────────────────────────────────────────────────┘
│ upgradepkg on every boot
│ (uses cache — no internet after first install)
▼
┌──────────────────────────────────────────────────────────────┐
│ RAM /usr/local/emhttp/plugins/claude-code/ │
│ (rebuilt each boot from .txz — never edit directly) │
│ │
│ claude-code.page ← Settings UI (Dynamix/PHP) │
│ default.cfg ← default config values │
│ README.md │
│ scripts/ │
│ ├── install-claude.sh ← restores binary from cache │
│ ├── setup-symlinks.sh ← manages /root/.claude link │
│ └── check-update.sh ← polls Anthropic releases │
│ event/ ← Unraid event system handlers │
│ ├── disks_mounted ← fires when /mnt/user ready │
│ ├── stopping_array ← fires before array stops │
│ └── started ← fires when boot complete │
│ php/ │
│ └── exec.php ← AJAX handler for UI actions │
└──────────────────────────────────────────────────────────────┘
│ symlinks /root/.claude (after disks_mounted)
▼
┌──────────────────────────────────────────────────────────────┐
│ Array /mnt/user/appdata/claude-code/ (user data) │
│ │
│ auth-token settings.json CLAUDE.md projects/ │
└──────────────────────────────────────────────────────────────┘
The .plg file uses YYYY.MM.DD date-based versioning and declares every downloaded file with a SHA256 checksum: <!ENTITY version "2026.04.07">
<FILE Name="/boot/config/plugins/claude-code/claude-code-&version;.txz">
<URL>https://github.com/you/repo/releases/download/&version;/claude-code-&version;.txz</URL>
<SHA256>a1b2c3d4e5f6789...</SHA256>
</FILE>
When a new plugin release is published, Unraid detects the newer date version and shows the standard update available notification in the Plugins page. The user clicks update, the new .txz is downloaded and verified, and updated scripts are live on next boot. Boot lifecycle and event handlingThis replaces the polling/wait-loop approach entirely. Three event handler scripts — delivered inside the .txz and placed in the plugin's event/ directory — handle the full lifecycle. Unraid's emhttp process calls them at exactly the right moments. BOOT
│
├─► Unraid extracts .txz via upgradepkg (from flash cache, no internet)
│ install-claude.sh restores Claude Code binary
│ setup-symlinks.sh sets initial fallback symlink:
│
│ /root/.claude ──► /tmp/.claude [FALLBACK MODE]
│
│ Claude Code is immediately usable for host-level tasks.
│ Array not required at this point.
│
├─► event/disks_mounted fires ◄── /mnt/user is now mounted and writable
│ setup-symlinks.sh switches symlink to appdata:
│
│ /root/.claude ──► /mnt/user/appdata/claude-code/ [FULL MODE]
│
│ Auth token, settings, and history are now accessible.
│
├─► event/started fires ◄── array startup fully complete
│ Logs active version and mode to syslog.
│ Sends optional WebUI notification (non-blocking).
│
│ ... normal operation ...
│
├─► event/stopping_array fires ◄── BEFORE unmounting begins
│ setup-symlinks.sh switches symlink back to /tmp:
│
│ /root/.claude ──► /tmp/.claude [FALLBACK MODE]
│
│ Claude Code stays functional throughout array stop.
│ Nothing writes to /mnt/user during or after unmount.
│
└─► Array stopped — plugin still running in fallback mode.
Available for maintenance, parity operations, drive diagnosis, etc.
disks_mounted is the correct event for appdata access — not started, not array_started. It fires specifically when /mnt/user shares are mounted and writable. stopping_array fires before unmounting begins, giving the plugin time to redirect writes before the filesystem disappears. started is used only for logging — nothing that could block the startup sequence. Fallback modeWhen the array is not running, Claude Code operates normally but without persistent config. The /root/.claude symlink points to /tmp/.claude in RAM. Claude Code has full access to the host filesystem for maintenance tasks, but nothing from the session survives a reboot. Auth tokens and settings are in appdata and unavailable until the array returns. Array state /root/.claude target Persistence
──────────────────────────────────────────────────────────────────
Array running /mnt/user/appdata/claude-code/ Full
Array stopped /tmp/.claude Session only
Array starting /tmp/.claude (until disks_mounted)
Array stopping /tmp/.claude (after stopping_array)
Settings pageThe plugin adds a page under Settings > Utilities > Claude Code, built using the Dynamix framework with standard .page file conventions. ┌──────────────────────────────────────────────────────────────┐
│ Settings > Utilities > Claude Code │
├──────────────────────────────────────────────────────────────┤
│ STATUS │
│ Plugin version: 2026.04.07 │
│ Claude Code: v2.0.71 │
│ Mode: Full (array running, appdata live) │
│ Auth token: Present │
│ Appdata path: /mnt/user/appdata/claude-code/ │
├──────────────────────────────────────────────────────────────┤
│ CLAUDE CODE BINARY UPDATES │
│ Installed: v2.0.71 │
│ Available: v2.0.74 │
│ ● Update available [Update Now] │
│ ▲ Security update (if CVE) [Update Now] │
│ Last checked: 2026-04-07 03:00 │
│ [x] Check for updates automatically (daily) │
├──────────────────────────────────────────────────────────────┤
│ CONFIGURATION │
│ Appdata path: [ /mnt/user/appdata/claude-code/ ] [Test] │
│ Auto-detected from Docker config │
│ [Apply] │
│ [View install log] [Re-run installer] │
├──────────────────────────────────────────────────────────────┤
│ SECURITY NOTICE (non-dismissible) │
│ Claude Code runs as root and has unrestricted access to │
│ all files, the Docker socket, the boot drive, and array │
│ contents. Always review proposed actions before │
│ confirming. Do not use --dangerously-skip-permissions in │
│ automated or unattended contexts. Never open untrusted │
│ project directories without reviewing .claude/ contents. │
└──────────────────────────────────────────────────────────────┘
The appdata path auto-detection from Docker config is carried forward from the existing implementations — it is a good usability feature that saves the majority of users from needing to configure anything. The [Test] button validates the path before saving, preventing the common misconfiguration where a path is entered that does not yet exist or is not writable. The install log viewer means users can diagnose installation problems without SSH — important for the broader Community Applications audience who may not be comfortable at the command line. Binary update strategyTwo separate update tracks operate independently. These must not be conflated — they change for different reasons and at different rates. TRACK 1: Plugin updates
(scripts, settings page, event hooks, config structure)
────────────────────────────────────────────────────────
Developer pushes new date-versioned tag to GitHub
│
▼
GitHub Actions builds .txz, computes SHA256,
updates .plg, publishes both to GitHub Releases
│
▼
Unraid plugin manager detects newer YYYY.MM.DD
│
▼
User clicks Update in Plugins page
│
▼
New .txz downloaded and SHA256 verified
Updated scripts active on next boot
TRACK 2: Claude Code binary updates
(Anthropic releases — including CVE patches)
────────────────────────────────────────────────────────
Daily cron job — check-update.sh — runs at 3am, non-blocking
│
▼
Polls Anthropic GitHub releases API for latest version
│
├── No update ──► exit silently, no notification
│
└── Update found
│
├── Standard release
│ Blue info badge in settings page
│ Bell notification in WebUI
│
└── Version in known CVE-affected range
Red warning badge in settings page
Urgent WebUI notification:
"Security update available for Claude Code"
User clicks "Update Now" in settings page
│
▼
Binary downloaded and SHA256 verified
Cached copy on flash replaced
Symlink updated — active immediately, no reboot required
Silent auto-update of the binary is deliberately not implemented. Anthropic ships updates frequently and has made breaking changes between major versions. On a server used for critical maintenance tasks, unexpected overnight changes are worse than a slightly older version. The user controls timing, with clear urgency signalling when security patches are involved. Repository structure and build pipelinerepo/
├── .github/
│ └── workflows/
│ └── release.yml ← triggered on version tag push:
│ 1. build.sh creates versioned .txz
│ 2. sha256sum computes checksum
│ 3. Checksum written into .plg
│ 4. Both published to GitHub Releases
│
├── source/
│ └── usr/local/emhttp/plugins/claude-code/
│ ├── claude-code.page ← Dynamix settings page (PHP)
│ ├── default.cfg ← default config values
│ ├── README.md ← shown in Plugin Manager
│ ├── scripts/
│ │ ├── install-claude.sh
│ │ ├── setup-symlinks.sh
│ │ └── check-update.sh
│ ├── event/
│ │ ├── disks_mounted ← must be chmod 755
│ │ ├── stopping_array ← must be chmod 755
│ │ └── started ← must be chmod 755
│ └── php/
│ └── exec.php
│
├── build.sh ← packages source/ into .txz:
│ 1. Strip CRLF line endings from scripts
│ 2. chmod 755 on all .sh and event handlers
│ 3. chmod 644 on .page, .cfg, .php files
│ 4. makepkg creates the .txz
│
├── claude-code.plg ← plugin installer XML
└── README.md
Two build-time requirements cause silent failures if missed. First, Windows line endings (CRLF) in any script file cause Slackware to reject it with a cryptic "bad interpreter" error. The build script must strip these even if the developer works only on Linux, because contributors using Windows editors can introduce them undetected. Second, event handler scripts that are not executable (chmod 755) are silently skipped by Unraid's event system with no error and no log entry. The build script must set permissions explicitly rather than relying on git or the packaging process to preserve them. What this design deliberately excludesNo bundled MCP servers. MCP server configuration files are where two of the three disclosed CVEs were found (CVE-2025-59356, CVE-2025-59536), allowing malicious commands to execute before user warnings appeared. Keeping MCP as a user-level concern means the plugin does not inherit responsibility for third-party MCP server security. Users who want MCP can add servers themselves via claude mcp add. No silent binary auto-updates. User-controlled, with urgency signalling for security-relevant versions, as described above. No hard dependency on other plugins. The plugin installs and operates independently. Users who want a richer WebUI terminal experience can separately install TTM (Tmux Terminal Manager) or the AI Tab plugin, but neither is required. No telemetry. No external calls beyond the Anthropic API that Claude Code itself makes. Security postureClaude Code running as root on the Unraid host has unrestricted access to the array, the boot drive, Docker socket, and all configuration files. This is precisely what makes it useful for server management, and precisely why the disclosure needs to be honest, persistent, and visible — in the README, in the settings page, and in a first-run notice before authentication completes. The disclosure should be factual rather than alarmist. Unraid users are generally comfortable with root-level tools. What they need is a clear understanding of scope before they start. Recommended practices to document for users: Read what Claude Code proposes before pressing Enter to confirm Avoid --dangerously-skip-permissions in any automated or scheduled context Never open a project directory cloned from an untrusted source without reviewing the .claude/ directory first — this is where the disclosed CVEs were triggered Keep the binary updated, particularly when the settings page shows a security warning badge Summary: design decisions and what they addressDecision Problem addressed Reference All runtime files in .txz No update mechanism for scripts plugin-docs: build-and-packaging SHA256 on every FILE element No integrity verification plugin-docs: plg-file Config in claude-code.cfg on flash Settings lost on reboot plugin-docs: plugin-settings-storage event/disks_mounted for appdata Polling race condition plugin-docs: events event/stopping_array for cleanup Writes during unmount plugin-docs: events event/started for logging Conventional boot signal plugin-docs: events Versioned .txz via GitHub Releases Broken update path plugin-docs: update-mechanisms YYYY.MM.DD versioning in .plg Update checker integration plugin-docs: plg-file Separate binary update track + cron CVE patches unreachable plugin-docs: cron-jobs Build script: CRLF strip + chmod Silent script failures plugin-docs: build-and-packaging Persistent security notice in UI Root access disclosure Thread feedback Fallback mode via /tmp/.claude Array-stopped usability Thread discussion Appdata path auto-detect Usability for new users Existing implementations Install log viewer in settings Diagnosis without SSH Thread discussion No bundled MCP CVE attack surface reduction CVE-2025-59356/59536 Plugin development documentation: https://plugin-docs.mstrhakr.com Anthropic Claude Code docs: https://docs.claude.com/en/docs/claude-code/overview