[cleo] claude config + new packages
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
# Personal instructions
|
||||
|
||||
## Where code lives
|
||||
- "The code", "the repo", "the monorepo", or any general code question refers to `~/Projects/cleo-infinite`.
|
||||
- Anything mentioning Retool refers to `~/Projects/cleo-retool`.
|
||||
|
||||
## Worktrees
|
||||
- Never write or edit code in the main checkouts (`~/Projects/cleo-infinite`, `~/Projects/cleo-retool`). Work in a treehouse worktree under `~/.treehouse/<repo>-<hash>/<slot>/<repo>`. Check with `git rev-parse --show-toplevel` and `git worktree list`.
|
||||
- If code changes are needed and the current directory is not a treehouse worktree, start one yourself without asking first, then continue there. Read-only investigation can stay where it is.
|
||||
- Treehouse is a zsh alias for `nix run github:kunchenguid/treehouse --`, so it is not on PATH in non-interactive shells. Run the full `nix run` form, and run it with `--help` first rather than guessing subcommands or flags.
|
||||
- Branch names follow the repo's own rules (cleo-infinite: `<JIRA-KEY>-short_slug` from latest `origin/main`). Take the Jira key from the user or the current branch. If there isn't one, ask. Never invent a key.
|
||||
- A pool slot sitting on a detached HEAD is not necessarily free. Don't reuse a slot that has uncommitted changes or that another session may be using.
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"environment": [
|
||||
"Organization: hicleo / Cleo (startwithlucy GitHub org; Jira at hicleo.atlassian.net)",
|
||||
"Cloud provider: AWS, accessed via SSO with Granted (`assume`, `assume -c`)",
|
||||
"Trusted repos: startwithlucy/cleo-infinite (origin) and git.thiccdata.io:mbessette/cleo-infinite.git (home). Both private, so confidential material is fine there, but secrets, PII and PHI are never cleared by visibility alone",
|
||||
"No internal snippet hosting exists: treat public paste and gist services as outside the trust boundary",
|
||||
"Secrets are held as CI secrets (CODECOMMIT_SSH_PRIVATE_KEY, CODECOMMIT_SSH_PRIVATE_KEY_ID, DD_API_KEY, GITHUB_TOKEN, JIRA_API_KEY, JIRA_EMAIL, SLACK_BOT_TOKEN, SNYK_KEY); never print or transmit their values",
|
||||
"Default branch is main. The `Copilot Review` ruleset is active and 100+ named branches are protected, so treat branches as protected even where classic protection lists are empty",
|
||||
"Trusted internal domain: hicleo.atlassian.net. sr71.sdet.hicleo.com (VPN-gated Jenkins) may be used interactively with $JENKINS_USER and $JENKINS_TOKEN from the shell env, never unattended",
|
||||
"Routine CLIs: mise, yarn (Yarn 4 workspaces), buf, assume/Granted, gh, jira",
|
||||
"Sensitive data locations: .env, .env.local, .env.test, .env.production and nested equivalents, *.key files, frontends/*/.env*, cicd/deploy-manager/chalicelib/code_prod_deploy_service.py, and infra-space/** terraform state and apply/plan/destroy scripts",
|
||||
"Sensitive remote targets: any namespace, host or container with `prod` or `production` as a whole word or segment, including pre-prod-enroll and enroll.hicleo.com",
|
||||
"Protected IaC scopes: infra-space/core/**, infra-space/environment/**, infra-space/applications/**, frontends/web-messaging/infra/**, plus IAM, RBAC, networking, quota and node-pool resources and anything named prod/production",
|
||||
"Claude Code runs on an ordinary developer machine with open internet; no host containment or network restrictions"
|
||||
],
|
||||
"allow": [],
|
||||
"soft_deny": [
|
||||
"Bash(terraform destroy:*) in infra-space/** and frontends/web-messaging/infra/**: protected IaC, prod-adjacent destructive apply",
|
||||
"Bash(rm:*) targeting infra-space/**/terraform.tfstate or any .tfstate file: irreversible state destruction"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
name: prod-db
|
||||
description: >-
|
||||
Look up data in Cleo production read replicas (Postgres, IAM auth, read-only).
|
||||
Use when the user asks to look up, find, or check something in prod / the prod
|
||||
DB, e.g. a user id, family id, guide id, or other record IDs for a given
|
||||
user. Returns IDs and metadata only, never PII/PHI.
|
||||
user-invocable: true
|
||||
argument-hint: '[question about prod data]'
|
||||
---
|
||||
# prod-db
|
||||
|
||||
Query prod read replicas through one script. Never call `psql` or `aws rds` directly.
|
||||
|
||||
```sh
|
||||
~/.config/claude/skills/prod-db/prod-query.sh <alias> "<select sql>"
|
||||
~/.config/claude/skills/prod-db/prod-query.sh <alias> --tables
|
||||
~/.config/claude/skills/prod-db/prod-query.sh <alias> --columns <table>
|
||||
```
|
||||
|
||||
The script connects to the `cluster-ro` endpoints as `reader`, forces read-only sessions with a 30s statement timeout, and caps output at 200 rows. If it reports no SSO session, ask the user to run `! aws sso login --profile prod-mono-reader`.
|
||||
|
||||
## PII/PHI rules (org policy: never put PII/PHI into Claude)
|
||||
|
||||
- SELECT only IDs, foreign keys, UUIDs, timestamps, statuses, flags and counts.
|
||||
- Never select names, emails, phones, DOB, addresses, notes, message bodies, health data, or Kratos `traits`. Never `SELECT *`.
|
||||
- A value the user gives you (an email) may appear only in a `WHERE` clause. Do not repeat it in your output; refer to "the user".
|
||||
- The script blocks `*`, non-SELECT statements, and result columns whose names look sensitive (it prints only the offending column names). Aliasing a sensitive column to dodge this is forbidden. If the user needs a PII field, tell them to look it up in Postico.
|
||||
- Report results as IDs only.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Pick the alias. Run `--tables` / `--columns <table>` (schema only) before writing SQL for an unfamiliar table.
|
||||
2. Write a narrow SELECT with explicit columns and a `LIMIT`.
|
||||
3. Summarize the IDs. Don't paste raw output beyond what's needed.
|
||||
|
||||
## Aliases
|
||||
|
||||
backend (backenddb), guides, kratos, userflow (userpreferencesdb), scheduling (schedulingdb), messaging (messagingdb), eligibility (eligibilitydb), entitlements (entitlementsdb), benefits (benefitsdb), assessments (assessmentsdb), engagement (engagementdb), tagging (taggingdb), supportplan (supportplandb), integrations, content (thegoodcontentdb), retool.
|
||||
|
||||
## Schema notes
|
||||
|
||||
**backend** (Django app `lucy_web`, `public` schema):
|
||||
- `auth_user(id, email)` is the user.
|
||||
- `lucy_web_family(id, employee_user_id, partner_user_id)` links a user to a family, as employee or partner.
|
||||
- `lucy_web_childfamilypackage(id, family_id, child_id, guide_id, guide_assigned_on)` links a family to its guide. The current guide is the row with the highest `id` for the family (see `Family.lucy_guide` in `services/cleo-backend/lucy_web/models/family.py`).
|
||||
- `lucy_web_lucyguide(id, uuid, user_id, is_active)` is the guide. `user_id` is the guide's own `auth_user` row. Do not select the guide's name or email.
|
||||
- Caregiver users are linked through the caregiver childfamilypackage models, which this query does not cover.
|
||||
|
||||
**guides**: tables store a numeric `guide_id` equal to `lucy_web_lucyguide.id`. It does not own the user-to-guide assignment.
|
||||
|
||||
**kratos**: `identities(id uuid, traits jsonb)`. The Kratos id is not known to equal backend `auth_user.id`. Bridge on email, inside `WHERE` only. Unverified for this deployment.
|
||||
|
||||
## Example: user id and guide id for an email
|
||||
|
||||
```sql
|
||||
select u.id as user_id, f.id as family_id,
|
||||
g.id as guide_id, g.uuid as guide_uuid, cfp.guide_assigned_on
|
||||
from auth_user u
|
||||
join lucy_web_family f on f.employee_user_id = u.id or f.partner_user_id = u.id
|
||||
join lucy_web_childfamilypackage cfp on cfp.family_id = f.id
|
||||
join lucy_web_lucyguide g on g.id = cfp.guide_id
|
||||
where lower(u.email) = lower('<email>')
|
||||
order by cfp.id desc
|
||||
limit 5
|
||||
```
|
||||
|
||||
Run it with alias `backend`.
|
||||
@@ -0,0 +1,16 @@
|
||||
backend prod-backend-aurora-cluster.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com backenddb
|
||||
guides prod-guides.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com guides
|
||||
kratos prod-orykratos.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com kratos
|
||||
userflow prod-userflow.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com userpreferencesdb
|
||||
scheduling prod-scheduling.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com schedulingdb
|
||||
messaging prod-messaging.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com messagingdb
|
||||
eligibility prod-eligibility.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com eligibilitydb
|
||||
entitlements prod-entitlements.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com entitlementsdb
|
||||
benefits prod-benefits.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com benefitsdb
|
||||
assessments prod-assessments.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com assessmentsdb
|
||||
engagement prod-engagement.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com engagementdb
|
||||
tagging prod-tagging.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com taggingdb
|
||||
supportplan prod-supportplan.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com supportplandb
|
||||
integrations prod-platformintegrations.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com integrations
|
||||
content prod-content.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com thegoodcontentdb
|
||||
retool prod-retoolpub.cluster-ro-czxwiektwmk0.us-east-1.rds.amazonaws.com retool
|
||||
|
Executable
+86
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
# Read-only lookups against prod read replicas (IAM auth). IDs/metadata only.
|
||||
#
|
||||
# prod-query.sh <alias> "<select sql>"
|
||||
# prod-query.sh <alias> --tables
|
||||
# prod-query.sh <alias> --columns <table>
|
||||
set -euo pipefail
|
||||
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROFILE="prod-mono-reader"
|
||||
REGION="us-east-1"
|
||||
DB_USER="reader"
|
||||
MAX_ROWS=200
|
||||
DENY_COLS='email|name|phone|birth|dob|address|street|zip|postal|ssn|traits|note|body|content|message|text|diagnos|medical|password|token|secret'
|
||||
|
||||
die() { echo "prod-query: $*" >&2; exit 1; }
|
||||
|
||||
[[ $# -ge 2 ]] || die "usage: prod-query.sh <alias> \"<select sql>\" | --tables | --columns <table>"
|
||||
|
||||
alias_name="$1"; shift
|
||||
row="$(awk -F'\t' -v a="$alias_name" '$1 == a { print; exit }' "$DIR/databases.tsv")"
|
||||
[[ -n "$row" ]] || die "unknown alias '$alias_name'. Known: $(cut -f1 "$DIR/databases.tsv" | paste -sd' ' -)"
|
||||
host="$(cut -f2 <<<"$row")"
|
||||
database="$(cut -f3 <<<"$row")"
|
||||
|
||||
internal=0
|
||||
case "$1" in
|
||||
--tables)
|
||||
internal=1
|
||||
sql="select table_schema, table_name from information_schema.tables where table_schema not in ('pg_catalog','information_schema') order by 1, 2"
|
||||
;;
|
||||
--columns)
|
||||
[[ $# -eq 2 ]] || die "--columns needs a table name"
|
||||
[[ "$2" =~ ^[A-Za-z0-9_.]+$ ]] || die "invalid table name"
|
||||
internal=1
|
||||
sql="select column_name, data_type from information_schema.columns where table_name = '${2##*.}' order by ordinal_position"
|
||||
;;
|
||||
*)
|
||||
sql="$1"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ $internal -eq 0 ]]; then
|
||||
sql="$(sed -E 's/[[:space:]]*;[[:space:]]*$//' <<<"$sql")"
|
||||
lc="$(tr '[:upper:]' '[:lower:]' <<<"$sql" | tr '\n' ' ')"
|
||||
|
||||
[[ "$lc" =~ ^[[:space:]]*(select|with)[[:space:]] ]] || die "only a single SELECT/WITH statement is allowed"
|
||||
[[ "$sql" != *";"* ]] || die "multiple statements are not allowed"
|
||||
[[ ! "$lc" =~ (^|[^a-z_])(insert|update|delete|drop|alter|create|grant|revoke|truncate|copy|call|do|set|reset|lock|vacuum|pg_read_file|pg_ls_dir|dblink|lo_import|lo_export)([^a-z_]|$) ]] \
|
||||
|| die "statement contains a disallowed keyword"
|
||||
|
||||
stripped="$(sed -E 's/count\([[:space:]]*\*[[:space:]]*\)//g' <<<"$lc")"
|
||||
[[ ! "$stripped" =~ (select|,)[[:space:]]*(distinct[[:space:]]+)?([a-z_0-9]+\.)?\* ]] \
|
||||
|| die "'*' in the select list is not allowed; list explicit ID/metadata columns (use --columns <table>)"
|
||||
fi
|
||||
|
||||
aws sts get-caller-identity --profile "$PROFILE" >/dev/null 2>&1 \
|
||||
|| die "no valid AWS SSO session. Run: ! aws sso login --profile $PROFILE"
|
||||
|
||||
PGPASSWORD="$(aws --profile "$PROFILE" rds generate-db-auth-token \
|
||||
--hostname "$host" --port 5432 --region "$REGION" --username "$DB_USER")"
|
||||
export PGPASSWORD
|
||||
export PGHOST="$host" PGPORT=5432 PGDATABASE="$database" PGUSER="$DB_USER" PGSSLMODE=require
|
||||
export PGOPTIONS="-c default_transaction_read_only=on -c statement_timeout=30000"
|
||||
|
||||
out="$(mktemp)"
|
||||
trap 'rm -f "$out"' EXIT
|
||||
psql -X --csv -v ON_ERROR_STOP=1 -c "$sql" >"$out"
|
||||
|
||||
header="$(head -n 1 "$out")"
|
||||
if [[ $internal -eq 0 ]]; then
|
||||
bad="$(tr ',' '\n' <<<"$header" | tr -d '"' | grep -Ei "$DENY_COLS" || true)"
|
||||
if [[ -n "$bad" ]]; then
|
||||
echo "prod-query: blocked, output columns look like PII/PHI (rows not shown):" >&2
|
||||
echo "$bad" >&2
|
||||
echo "Select IDs/metadata only; use these fields only inside WHERE." >&2
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
total=$(( $(wc -l <"$out") - 1 ))
|
||||
head -n $(( MAX_ROWS + 1 )) "$out" \
|
||||
| sed -E 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/<redacted-email>/g'
|
||||
if (( total > MAX_ROWS )); then
|
||||
echo "prod-query: output truncated to $MAX_ROWS of $total rows" >&2
|
||||
fi
|
||||
+18
-4
@@ -71,9 +71,13 @@ in
|
||||
ttyd
|
||||
xcodes
|
||||
xz
|
||||
# node 22 pinned to the exact version cleo-app requires (nixpkgs-nodejs in flake.nix)
|
||||
pinnedNode.nodejs_22
|
||||
pinnedNode.yarn
|
||||
# node 24.x from unstable (cached); the pinnedNode 24.19.0 rev had no cache.nixos.org binaries
|
||||
unstable.nodejs_24
|
||||
unstable.yarn
|
||||
# iOS simulator UI driving (tap/scroll/type) for screenshots and e2e flows
|
||||
unstable.maestro
|
||||
unstable.idb-companion
|
||||
act
|
||||
];
|
||||
|
||||
# Add Homebrew to PATH
|
||||
@@ -147,6 +151,16 @@ in
|
||||
);
|
||||
};
|
||||
|
||||
nix.settings.experimental-features = "nix-command flakes";
|
||||
nix = {
|
||||
settings = {
|
||||
experimental-features = "nix-command flakes";
|
||||
auto-optimise-store = true;
|
||||
};
|
||||
gc = {
|
||||
automatic = true;
|
||||
interval = { Weekday = 0; Hour = 2; Minute = 0; }; # Sunday at 2:00 AM
|
||||
options = "--delete-older-than 7d";
|
||||
};
|
||||
};
|
||||
system.stateVersion = 4;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
{ config, pkgs, vars, ... }:
|
||||
let
|
||||
# Agent/skill bodies live in the cleo-infinite checkout; symlinked so they
|
||||
# follow upstream on every pull.
|
||||
ansibleFiles = "${config.home.homeDirectory}/Projects/cleo-infinite/scripts/local-dev-ansible/files";
|
||||
linkAnsibleFile = name: config.lib.file.mkOutOfStoreSymlink "${ansibleFiles}/${name}";
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./programs.vscode.nix
|
||||
@@ -96,6 +102,23 @@
|
||||
};
|
||||
};
|
||||
|
||||
# Claude Code (tasks/config/claude-code.yml). The remaining settings keys
|
||||
# (additionalDirectories, statusLine, ...) come from home.shared.nix.
|
||||
my.claude.settings = {
|
||||
awaySummaryEnabled = false;
|
||||
promptSuggestionEnabled = false;
|
||||
# Generated by /auto-mode-setup; kept as JSON so it can be re-pasted and diffed.
|
||||
autoMode = builtins.fromJSON (builtins.readFile ./claude/auto-mode.json);
|
||||
};
|
||||
xdg.configFile."claude/agents/Explore.md".source = linkAnsibleFile "claude-explore-agent.md";
|
||||
xdg.configFile."claude/agents/orchestrator-sonnet.md".source = linkAnsibleFile "claude-orchestrator-sonnet-agent.md";
|
||||
xdg.configFile."claude/agents/orchestrator-opus.md".source = linkAnsibleFile "claude-orchestrator-opus-agent.md";
|
||||
xdg.configFile."claude/skills/orchestrate/SKILL.md".source = linkAnsibleFile "claude-orchestrate-skill.md";
|
||||
xdg.configFile."claude/CLAUDE.md".source =
|
||||
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/nixos/claude/CLAUDE.md";
|
||||
xdg.configFile."claude/skills/prod-db".source =
|
||||
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/nixos/claude/skills/prod-db";
|
||||
|
||||
# opencode (tasks/config/opencode.yml)
|
||||
xdg.configFile."opencode/opencode.json".text = builtins.toJSON {
|
||||
"$schema" = "https://opencode.ai/config.json";
|
||||
|
||||
Generated
+4
-4
@@ -254,17 +254,17 @@
|
||||
},
|
||||
"nixpkgs-nodejs": {
|
||||
"locked": {
|
||||
"lastModified": 1737545071,
|
||||
"narHash": "sha256-j4HeaLw1LZxkCvuOxdO1xTnPYLSOQuzOjGEuCK80X2w=",
|
||||
"lastModified": 1785767437,
|
||||
"narHash": "sha256-1FG0hlMWqs1Yh3NJzt5ejMRqhJdSsr1qMqiAgMO3ZKs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "21808d22b1cda1898b71cf1a1beb524a97add2c4",
|
||||
"rev": "700ca73b459b479645c7e5a957def679414c886f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "21808d22b1cda1898b71cf1a1beb524a97add2c4",
|
||||
"rev": "700ca73b459b479645c7e5a957def679414c886f",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
|
||||
nix-flatpak.url = "github:gmodena/nix-flatpak/main";
|
||||
|
||||
# Pinned nixpkgs for a specific nodejs_22 + yarn version required by cleo-app
|
||||
nixpkgs-nodejs.url = "github:NixOS/nixpkgs/21808d22b1cda1898b71cf1a1beb524a97add2c4";
|
||||
# Pinned nixpkgs for a specific nodejs_24 (24.19.0) + yarn version required by cleo-app
|
||||
nixpkgs-nodejs.url = "github:NixOS/nixpkgs/700ca73b459b479645c7e5a957def679414c886f";
|
||||
};
|
||||
|
||||
outputs =
|
||||
|
||||
+19
-19
@@ -15,6 +15,8 @@ let
|
||||
rebuildCmd = if pkgs.stdenv.isDarwin then "darwin-rebuild" else "nixos-rebuild";
|
||||
in
|
||||
{
|
||||
imports = [ ./module.claude.nix ];
|
||||
|
||||
home.stateVersion = lib.mkDefault "26.05";
|
||||
home.username = userConfig.username;
|
||||
home.homeDirectory = userConfig.homeDirectory;
|
||||
@@ -41,25 +43,23 @@ in
|
||||
vault = "${userConfig._1PassKeyVault}"
|
||||
'';
|
||||
|
||||
xdg.configFile."claude/settings.json".source = pkgs.writeText "claude-settings.json" (
|
||||
builtins.toJSON {
|
||||
"$schema" = "https://json.schemastore.org/claude-code-settings.json";
|
||||
theme = "dark";
|
||||
agent = "plan";
|
||||
denyCommands = [ "code --install-extension*" ];
|
||||
additionalDirectories = [ "/tmp" ];
|
||||
autoMemoryEnabled = false;
|
||||
effortLevel = "medium";
|
||||
fastModePerSessionOptIn = true;
|
||||
feedbackSurveyRate = 0;
|
||||
model = "opusplan";
|
||||
showClearContextOnPlanAccept = false;
|
||||
statusLine = {
|
||||
type = "command";
|
||||
command = "claude-statusline prompt";
|
||||
};
|
||||
}
|
||||
);
|
||||
my.claude.settings = {
|
||||
"$schema" = "https://json.schemastore.org/claude-code-settings.json";
|
||||
theme = "dark";
|
||||
agent = "plan";
|
||||
denyCommands = [ "code --install-extension*" ];
|
||||
additionalDirectories = [ "/tmp" ];
|
||||
autoMemoryEnabled = false;
|
||||
effortLevel = "medium";
|
||||
fastModePerSessionOptIn = true;
|
||||
feedbackSurveyRate = 0;
|
||||
model = "opusplan";
|
||||
showClearContextOnPlanAccept = false;
|
||||
statusLine = {
|
||||
type = "command";
|
||||
command = "claude-statusline prompt";
|
||||
};
|
||||
};
|
||||
|
||||
xdg.configFile."claude-statusline/config.toml".text = ''
|
||||
format = "$directory | $git_branch | $model | $cost | $context | $usage"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
jsonFormat = pkgs.formats.json { };
|
||||
in
|
||||
{
|
||||
# Host modules contribute keys here; the module system deep-merges them into
|
||||
# a single ~/.config/claude/settings.json.
|
||||
options.my.claude.settings = lib.mkOption {
|
||||
type = jsonFormat.type;
|
||||
default = { };
|
||||
description = "Claude Code settings.json contents.";
|
||||
};
|
||||
|
||||
config.xdg.configFile."claude/settings.json".source =
|
||||
jsonFormat.generate "claude-settings.json" config.my.claude.settings;
|
||||
}
|
||||
Reference in New Issue
Block a user