<?xml version="1.0"?>
<!-- AI Shuffle Unraid template, v2. Community repository layout: this folder
     is published as github.com/HobbyCoders/ai-shuffle-unraid (see README.md).
     Keep the Repository tag equal to the current release; a test in the
     private repository checks it. -->
<Container version="2">
  <Name>AI-Shuffle</Name>
  <Repository>registry.hobbycoders.com/YOUR-PULL-TOKEN/ai-shuffle:0.9.1</Repository>
  <Registry>https://hobbycoders.com/ai-shuffle</Registry>
  <Network>bridge</Network>
  <MyIP/>
  <Shell>bash</Shell>
  <Privileged>false</Privileged>
  <Support>https://github.com/HobbyCoders/ai-shuffle-unraid/issues</Support>
  <Project>https://hobbycoders.com/ai-shuffle</Project>
  <Overview>
    AI Shuffle is a self-hosted workspace for AI coding agents. It runs AI agents with your own AI provider account (Claude, OpenAI, OpenRouter, xAI Grok or a custom gateway), by subscription sign-in or API key, keeps projects and sessions on your server, and includes a built-in browser for agents.&#xD;
    &#xD;
    Requires an AI Shuffle license. Replace YOUR-PULL-TOKEN in the Repository field with the pull token from your license email.&#xD;
    &#xD;
    Set "WebUI address" to this server's LAN address followed by :8000 (for example 192.168.1.20:8000), not a bare port.&#xD;
    &#xD;
    Agents' Python code runs inside a sandbox with no network and none of the server's files. The --security-opt entries in Extra Parameters allow it; they turn off Docker's default seccomp and AppArmor filters and its /proc masking for the whole container. To opt out, remove them in Advanced View or set the Code-mode sandbox variable to off. Settings, Security, Code sandbox shows whether the sandbox is active. See "The code-mode sandbox" in the install guide.
  </Overview>
  <Category>Productivity: Tools:Utilities</Category>
  <WebUI>http://[IP]:8000/</WebUI>
  <TemplateURL>https://raw.githubusercontent.com/HobbyCoders/ai-shuffle-unraid/main/ai-shuffle.xml</TemplateURL>
  <Icon>https://hobbycoders.com/ai-shuffle/icon.png</Icon>
  <!-- shm-size: Chromium needs more than Docker's 64 MB /dev/shm.
       stop-timeout: agents stop first, then PostgreSQL writes a clean
       checkpoint; this can take up to 90 seconds.
       init and pids-limit: reap and bound the many short-lived agent processes.
       security-opt: the code-mode sandbox (bubblewrap) needs user namespaces
       and a fresh /proc mount; Docker ignores apparmor=unconfined on hosts
       without AppArmor, such as Unraid. -->
  <ExtraParams>--init --pids-limit=8192 --shm-size=1g --stop-timeout=90 --security-opt seccomp=unconfined --security-opt systempaths=unconfined --security-opt apparmor=unconfined</ExtraParams>
  <PostArgs/>
  <CPUset/>
  <DateInstalled/>
  <DonateText/>
  <DonateLink/>
  <Requires>An AI Shuffle license and its pull token (hobbycoders.com). A 64-bit Intel or AMD server with at least 4 GB of free memory (8 GB or more recommended).</Requires>
  <Config Name="WebUI address" Target="8000" Default="" Mode="tcp" Description="This server's LAN address and port, for example 192.168.1.20:8000. The web UI then listens on that one address only. A bare port (8000) would publish it on every interface, including VPN and Docker networks. Never forward it from your router." Type="Port" Display="always" Required="true" Mask="false"></Config>
  <Config Name="Owner password" Target="OWNER_PASSWORD" Default="" Mode="" Description="The password every browser signs in with. Read on the first start only: change it later in Settings, Security, Owner password (you can then clear this field). Leave empty to create it in your browser on first visit. At least 12 characters." Type="Variable" Display="always" Required="false" Mask="true"></Config>
  <Config Name="License key" Target="LICENSE_KEY" Default="" Mode="" Description="Optional. Your license key (ASH-XXXXX-XXXXX-XXXXX-XXXXX) from your license email. Activated for this server on the first start, then ignored: you can clear this field afterwards. Leave empty to paste the key in Settings, System, License instead. Not used while the beta runs." Type="Variable" Display="always" Required="false" Mask="true"></Config>
  <Config Name="Workspace" Target="/workspace" Default="/mnt/user/appdata/ai-shuffle/workspace" Mode="rw" Description="Your projects. Point it at a share if you want to open the files from other computers." Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/ai-shuffle/workspace</Config>
  <Config Name="Data" Target="/data" Default="/mnt/user/appdata/ai-shuffle/data" Mode="rw" Description="Database, encryption key, sessions and logs. Back this up together with the other appdata folders." Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/ai-shuffle/data</Config>
  <Config Name="Browser profile" Target="/home/appuser/chrome-profile" Default="/mnt/user/appdata/ai-shuffle/browser-profile" Mode="rw" Description="The built-in browser's profile, so sites you signed in to stay signed in after an update." Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/ai-shuffle/browser-profile</Config>
  <Config Name="Settings" Target="/home/appuser/.fluid" Default="/mnt/user/appdata/ai-shuffle/settings" Mode="rw" Description="AI Shuffle settings." Type="Path" Display="advanced" Required="true" Mask="false">/mnt/user/appdata/ai-shuffle/settings</Config>
  <Config Name="Claude Code login" Target="/home/appuser/.claude" Default="/mnt/user/appdata/ai-shuffle/claude" Mode="rw" Description="The Claude Code CLI's own login and settings." Type="Path" Display="advanced" Required="true" Mask="false">/mnt/user/appdata/ai-shuffle/claude</Config>
  <Config Name="Claude Code CLI" Target="/home/appuser/.local" Default="/mnt/user/appdata/ai-shuffle/local" Mode="rw" Description="The Claude Code CLI and its updates. Downloaded with Anthropic's installer when you choose Claude and install it from Settings or setup. Reinstalled at start only while Keep Claude Code installed is on." Type="Path" Display="advanced" Required="true" Mask="false">/mnt/user/appdata/ai-shuffle/local</Config>
  <Config Name="GitHub CLI login" Target="/home/appuser/.config/gh" Default="/mnt/user/appdata/ai-shuffle/gh" Mode="rw" Description="GitHub CLI sign-in." Type="Path" Display="advanced" Required="true" Mask="false">/mnt/user/appdata/ai-shuffle/gh</Config>
  <Config Name="PUID" Target="PUID" Default="99" Mode="" Description="User ID that owns the appdata folders (99 is Unraid's nobody)." Type="Variable" Display="advanced" Required="true" Mask="false">99</Config>
  <Config Name="PGID" Target="PGID" Default="100" Mode="" Description="Group ID that owns the appdata folders (100 is Unraid's users)." Type="Variable" Display="advanced" Required="true" Mask="false">100</Config>
  <Config Name="Secure cookies" Target="COOKIE_SECURE" Default="false" Mode="" Description="false for plain http:// on your LAN. Set true when you reach AI Shuffle only through HTTPS (a reverse proxy or Tailscale Serve)." Type="Variable" Display="advanced" Required="false" Mask="false">false</Config>
  <Config Name="Log level" Target="LOG_LEVEL" Default="info" Mode="" Description="debug, info, warning or error." Type="Variable" Display="advanced" Required="false" Mask="false">info</Config>
  <Config Name="Trusted proxies" Target="TRUSTED_PROXIES" Default="" Mode="" Description="Optional. The address of a reverse proxy in another container or on this server, as AI Shuffle sees it (comma-separated IPs or ranges). Without it, the audit log and the pairing and network-join attempt limits see every visitor as the proxy. Never list your whole LAN." Type="Variable" Display="advanced" Required="false" Mask="false"></Config>
  <Config Name="Code-mode sandbox" Target="CODE_MODE_OS_SANDBOX" Default="" Mode="" Description="Optional. auto (the default when empty), required or off. Whether agents' Python code runs inside a sandbox with no network and none of the server's files. auto uses it while the --security-opt entries in Extra Parameters allow it (they do as shipped) and otherwise runs without it, with one log line; required refuses to run code without it. Settings, Security, Code sandbox shows the state." Type="Variable" Display="advanced" Required="false" Mask="false"></Config>
  <Config Name="Browser allowed ranges" Target="BROWSER_SSRF_ALLOW" Default="" Mode="" Description="Optional. Address ranges the built-in browser may open, comma-separated. Empty keeps the default: localhost inside the container, but not your LAN or Tailscale addresses. A value replaces that default, so start with 127.0.0.0/8,::1/128 to keep localhost. To refuse localhost as well, add a variable BROWSER_SSRF_ALLOW_LOOPBACK set to false and leave this empty." Type="Variable" Display="advanced" Required="false" Mask="false"></Config>
  <Config Name="Browser blocked ranges" Target="BROWSER_SSRF_BLOCK" Default="" Mode="" Description="Optional. Address ranges the built-in browser refuses even if the allowed ranges list them, comma-separated." Type="Variable" Display="advanced" Required="false" Mask="false"></Config>
</Container>
