一键导入
torvalds-deployment
Use when asking about adding services, createXxxDeployment patterns, or homelab deployment conventions. Services use per-namespace charts.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when asking about adding services, createXxxDeployment patterns, or homelab deployment conventions. Services use per-namespace charts.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
BuildKite CI/CD pipeline configuration, YAML syntax, dynamic pipelines, and agent management When user works with BuildKite, mentions CI pipelines, .buildkite/ directory, buildkite-agent commands, pipeline YAML, build steps, BuildKite API, or asks about CI configuration, pipeline generation, step dependencies, retry configuration, agent queues, or Kubernetes CI agents
Check PR health status (conflicts, CI, approval) and get actionable next steps
Monitor a PR through reviews and merge conflicts until ready for human review. Use when user says "monitor PR", "watch PR", or wants automated PR workflow. Creates PR if needed, then monitors review comments and merge conflicts. Note: this monorepo's CI runs on Buildkite (`buildkite/monorepo/pr` + `ci/merge-conflict`) per PR — watch it via `bk build view` or the Buildkite web UI, not `gh run`.
Use when asking about generating Helm types, HelmValuesForChart, TypeScript interfaces from Helm charts, or the helm-types CLI.
Talos Linux cluster administration using talosctl When user mentions Talos, talosctl, or Talos cluster operations
Use when asking about version management, Renovate annotations, versions.ts patterns, or pinning image/chart versions.
| name | torvalds-deployment |
| description | Use when asking about adding services, createXxxDeployment patterns, or homelab deployment conventions. Services use per-namespace charts. |
Services are deployed across multiple namespaces using an app-of-apps pattern. Each service
category has its own namespace and Helm chart (e.g., media, home, postal). Services follow
a consistent createXxxDeployment() pattern.
The cluster (torvalds) has no imagePullSecret / dockerconfigjson infrastructure anywhere in
src/cdk8s. Every first-party image (ghcr.io/shepherdjerred/*) must therefore be a public ghcr
package; a private package makes kubelet pull anonymously, ghcr returns 401 Unauthorized →
ImagePullBackOff.
Newly-created ghcr packages default to private, so a brand-new service breaks on first deploy
until its package is flipped to public — even when versions.ts has the correct digest (digests are
updated manually in versions.ts since the CI commit-back was removed 2026-07; visibility is separate).
Check visibility without cluster access:
tok=$(curl -s "https://ghcr.io/token?scope=repository:shepherdjerred/<pkg>:pull&service=ghcr.io" | python3 -c 'import sys,json;print(json.load(sys.stdin).get("token",""))')
curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $tok" "https://ghcr.io/v2/shepherdjerred/<pkg>/tags/list" # 200=public, 403=private
Changing visibility is GitHub-UI only (no REST API; the default gh token lacks write:packages):
the owner must set it at
https://github.com/users/shepherdjerred/packages/container/<pkg>/settings → Danger Zone → Change
visibility → Public. Ask the user — you cannot do this.
| Namespace | Services | Chart File |
|---|---|---|
media | Plex, Radarr, Sonarr, Bazarr, Prowlarr, etc. | media.ts |
home | Home Assistant, HA automations | home.ts |
postal | Postal mail server, MariaDB | postal.ts |
syncthing | Syncthing | syncthing.ts |
golink | GoLink | golink.ts |
freshrss | FreshRSS | freshrss.ts |
pokemon | Pokemon bots | pokemon.ts |
gickup | Gickup | gickup.ts |
Create src/cdk8s/src/resources/{category}/yourservice.ts:
import { Chart, Size } from "cdk8s";
import {
Cpu,
Deployment,
DeploymentStrategy,
type PersistentVolumeClaim,
Service,
Volume,
} from "cdk8s-plus-31";
import {
LINUXSERVER_GID,
withCommonLinuxServerProps,
} from "../../misc/linux-server.ts";
import { ZfsNvmeVolume } from "../../misc/zfs-nvme-volume.ts";
import { TailscaleIngress } from "../../misc/tailscale.ts";
import versions from "../../versions.ts";
export function createYourServiceDeployment(
chart: Chart,
claims?: {
downloads?: PersistentVolumeClaim;
media?: PersistentVolumeClaim;
},
) {
// 1. Create Deployment
const deployment = new Deployment(chart, "yourservice", {
replicas: 1,
strategy: DeploymentStrategy.recreate(),
securityContext: {
fsGroup: LINUXSERVER_GID,
},
});
// 2. Create config volume (SSD for performance)
const configVolume = new ZfsNvmeVolume(chart, "yourservice-pvc", {
storage: Size.gibibytes(8),
});
// 3. Add container
deployment.addContainer(
withCommonLinuxServerProps({
image: `ghcr.io/linuxserver/yourservice:${versions["linuxserver/yourservice"]}`,
portNumber: 8080,
volumeMounts: [
{
path: "/config",
volume: Volume.fromPersistentVolumeClaim(
chart,
"yourservice-config-volume",
configVolume.claim,
),
},
// Add shared volumes if needed
...(claims?.downloads
? [
{
path: "/downloads",
volume: Volume.fromPersistentVolumeClaim(
chart,
"yourservice-downloads-volume",
claims.downloads,
),
},
]
: []),
],
resources: {
cpu: {
request: Cpu.millis(100),
limit: Cpu.millis(1000),
},
memory: {
request: Size.mebibytes(256),
limit: Size.mebibytes(512),
},
},
}),
);
// 4. Create Service
const service = new Service(chart, "yourservice-service", {
selector: deployment,
ports: [{ port: 8080 }],
});
// 5. Create Tailscale Ingress
new TailscaleIngress(chart, "yourservice-ingress", {
service,
host: "yourservice",
});
}
Edit src/cdk8s/src/versions.ts:
const versions = {
// renovate: datasource=docker registryUrl=https://ghcr.io versioning=docker
"linuxserver/yourservice": "1.0.0@sha256:abc123...",
// ... other versions
};
For media services, edit src/cdk8s/src/cdk8s-charts/media.ts:
import { createYourServiceDeployment } from "../resources/media/yourservice.ts";
export function createMediaChart(app: App) {
const chart = new Chart(app, "media", {
namespace: "media",
disableResourceNameHashes: true,
});
// Shared volumes
const downloadsVolume = new ZfsSataVolume(chart, "downloads-hdd-pvc", {
storage: Size.tebibytes(1),
});
// Add your service
createYourServiceDeployment(chart, {
downloads: downloadsVolume.claim,
});
// ... rest of chart
}
If creating a new namespace, add ArgoCD app in src/cdk8s/src/resources/argo-applications/yournamespace.ts:
import { Chart } from "cdk8s";
import { Application } from "../../generated/imports/argoproj.io.ts";
import { createArgoApplication } from "./common.ts";
export function createYourNamespaceApplication(chart: Chart) {
return createArgoApplication(chart, "yournamespace", {
chart: {
repoUrl: "https://chartmuseum.tailnet-1a49.ts.net",
chartName: "yournamespace",
},
destination: {
namespace: "yournamespace",
},
});
}
Then register in src/cdk8s/src/cdk8s-charts/apps.ts. (Charts were also listed in HELM_CHARTS in .dagger/src/helm.ts for the automated helm package/push, but that pipeline was removed 2026-07 — chart packaging/publishing to ChartMuseum is manual now.)
// Main container
deployment.addContainer(
withCommonLinuxServerProps({
image: `...`,
portNumber: 8080,
}),
);
// Metrics sidecar
deployment.addContainer(
withCommonProps({
name: "exporter",
image: `...`,
ports: [{ number: 9090, name: "metrics" }],
securityContext: {
ensureNonRoot: true,
readOnlyRootFilesystem: true,
user: 65534,
group: 65534,
},
}),
);
import { ServiceMonitor } from "../../generated/imports/monitoring.coreos.com.ts";
new ServiceMonitor(chart, "yourservice-monitor", {
metadata: {
name: "yourservice-monitor",
labels: { release: "prometheus" },
},
spec: {
endpoints: [{ port: "metrics", interval: "60s", path: "/metrics" }],
selector: { matchLabels: { app: "yourservice" } },
},
});
import { OnePasswordItem } from "../../generated/imports/onepassword.com.ts";
const secrets = new OnePasswordItem(chart, "yourservice-secrets", {
spec: {
itemPath: "vaults/xxx/items/yyy",
},
});
// Use in container
envVariables: {
API_KEY: EnvValue.fromSecretValue({
secret: Secret.fromSecretName(chart, "api-key", secrets.name),
key: "password",
}),
},
new TailscaleIngress(chart, "yourservice-ingress", {
service,
host: "yourservice",
funnel: true, // Accessible from public internet
});
src/cdk8s/src/
├── cdk8s-charts/
│ ├── media.ts # Media namespace chart
│ ├── home.ts # Home namespace chart
│ ├── postal.ts # Postal namespace chart
│ └── ... # Other namespace charts
├── resources/
│ ├── torrents/ # Sonarr, Radarr, qBittorrent
│ ├── media/ # Plex, Tautulli, etc.
│ ├── home/ # Home Assistant
│ ├── mail/ # Postal mail server
│ └── argo-applications/ # ArgoCD app definitions
└── helm/
├── media/ # Media Helm chart
├── home/ # Home Helm chart
└── ... # Other Helm charts
src/cdk8s/src/cdk8s-charts/media.ts - Media namespace chartsrc/cdk8s/src/cdk8s-charts/home.ts - Home namespace chartsrc/cdk8s/src/resources/torrents/sonarr.ts - Reference examplesrc/cdk8s/src/resources/media/plex.ts - Complex example with sidecars