feat(nix): add Nextcloud Claude Bot integration
- Added configuration for Nextcloud Claude Bot, including NixOS module, secrets management, and example setup files. - Introduced a Python-based HTTP server for handling webhook events and interacting with Nextcloud Talk. - Integrated necessary dependencies and systemd service for seamless operation.
This commit is contained in:
parent
eb10ad018f
commit
bc6091f63f
7 changed files with 728 additions and 0 deletions
141
systems/x86_64-linux/mx/nextcloud-claude-bot/module.nix
Normal file
141
systems/x86_64-linux/mx/nextcloud-claude-bot/module.nix
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.nextcloud-claude-bot;
|
||||
|
||||
botScript = pkgs.python3Packages.buildPythonApplication {
|
||||
pname = "nextcloud-claude-bot";
|
||||
version = "0.1.0";
|
||||
format = "other";
|
||||
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [
|
||||
fastapi
|
||||
uvicorn
|
||||
httpx
|
||||
];
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cp ${./bot.py} $out/bin/nextcloud-claude-bot
|
||||
chmod +x $out/bin/nextcloud-claude-bot
|
||||
'';
|
||||
};
|
||||
|
||||
in {
|
||||
options.services.nextcloud-claude-bot = {
|
||||
enable = mkEnableOption "Nextcloud Talk Claude Bot";
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8085;
|
||||
description = "Port for the webhook listener";
|
||||
};
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "Host to bind to";
|
||||
};
|
||||
|
||||
nextcloudUrl = mkOption {
|
||||
type = types.str;
|
||||
example = "https://cloud.example.com";
|
||||
description = "Base URL of your Nextcloud instance";
|
||||
};
|
||||
|
||||
botSecretFile = mkOption {
|
||||
type = types.path;
|
||||
description = "Path to file containing the bot secret (shared with Nextcloud)";
|
||||
};
|
||||
|
||||
claudePath = mkOption {
|
||||
type = types.path;
|
||||
default = "${pkgs.claude-code}/bin/claude";
|
||||
description = "Path to claude CLI binary";
|
||||
};
|
||||
|
||||
allowedUsers = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "harald" "admin" ];
|
||||
description = "Nextcloud usernames allowed to talk to the bot (empty = all)";
|
||||
};
|
||||
|
||||
maxTokens = mkOption {
|
||||
type = types.int;
|
||||
default = 4096;
|
||||
description = "Max tokens for Claude response";
|
||||
};
|
||||
|
||||
timeout = mkOption {
|
||||
type = types.int;
|
||||
default = 120;
|
||||
description = "Timeout in seconds for Claude CLI";
|
||||
};
|
||||
|
||||
systemPrompt = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "Du bist ein hilfreicher Assistent.";
|
||||
description = "Optional system prompt for Claude";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.nextcloud-claude-bot = {
|
||||
description = "Nextcloud Talk Claude Bot";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
environment = {
|
||||
BOT_HOST = cfg.host;
|
||||
BOT_PORT = toString cfg.port;
|
||||
NEXTCLOUD_URL = cfg.nextcloudUrl;
|
||||
CLAUDE_PATH = cfg.claudePath;
|
||||
ALLOWED_USERS = concatStringsSep "," cfg.allowedUsers;
|
||||
MAX_TOKENS = toString cfg.maxTokens;
|
||||
TIMEOUT = toString cfg.timeout;
|
||||
SYSTEM_PROMPT = cfg.systemPrompt or "";
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
ExecStart = "${pkgs.python3Packages.uvicorn}/bin/uvicorn nextcloud_claude_bot:app --host ${cfg.host} --port ${toString cfg.port}";
|
||||
Restart = "always";
|
||||
RestartSec = 5;
|
||||
|
||||
# Security hardening
|
||||
DynamicUser = true;
|
||||
NoNewPrivileges = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = "read-only";
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
MemoryDenyWriteExecute = false; # Python needs this
|
||||
LockPersonality = true;
|
||||
|
||||
# Bot secret
|
||||
LoadCredential = "bot-secret:${cfg.botSecretFile}";
|
||||
|
||||
# Claude CLI needs home for config
|
||||
StateDirectory = "nextcloud-claude-bot";
|
||||
Environment = "HOME=/var/lib/nextcloud-claude-bot";
|
||||
};
|
||||
};
|
||||
|
||||
# Nginx reverse proxy config (optional, if you want external access)
|
||||
# services.nginx.virtualHosts."cloud.example.com".locations."/claude-bot/" = {
|
||||
# proxyPass = "http://${cfg.host}:${toString cfg.port}/";
|
||||
# };
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue