ワンクリックで
deploy
Use when deploying a pocopine full-stack or static app to Fly.io, Railway, Render, or other hosts using the RFC 080 deploy contract
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when deploying a pocopine full-stack or static app to Fly.io, Railway, Render, or other hosts using the RFC 080 deploy contract
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Use when turning a Claude Design (or any mockup/design) into a well-structured pocopine app — choosing app architecture (a store plus layout/leaf components), translating inline styles into Pine Stylekit, wiring icons and resizable regions, and verifying the result.
Use when working with the pocopine Pine icons feature — the `icon!` proc macro for compile-time Rust SVG embedding, or the `<pine-icon>` template primitive with `register_icons!` for tree-shaking-friendly template rendering.
Use when building styles with Pine Stylekit, the Pocopine-native utility-CSS compiler, or working with @theme tokens and CSS generation in Rust/WASM projects
Use when building enter/leave transitions, layout animations, stagger effects, or spring-physics motion in pocopine components
Use when implementing authentication in pocopine apps — JWT verification, credentials, OAuth providers, session management, or guards
Use when defining background jobs, enqueueing work, configuring workers, or troubleshooting job execution in pocopine apps
| name | deploy |
| description | Use when deploying a pocopine full-stack or static app to Fly.io, Railway, Render, or other hosts using the RFC 080 deploy contract |
The pocopine deployment system is a Heroku-style process model (RFC 080) that decouples app config from host-specific infrastructure. Write one portable [deploy] block in Pocopine.toml; adapters translate it to Fly/Railway/Render native configs. Switching hosts is --target fly → --target railway, nothing else.
[deploy] blocks in Pocopine.tomlpocopine deploy --target <host>, pocopine deploy auth, pocopine deploy doctorweb and worker processes for jobs + collabPocopine.toml [deploy] block[deploy]
mode = "fullstack" # "fullstack" | "static"
[deploy.processes.web]
bin = "server" # cargo bin name (required)
port = 8080 # public HTTP port
healthcheck = "/healthz" # optional HTTP health endpoint
scale = { min = 1, max = 5 } # replicas (min/max)
public = true # default true if port set; false hides from ingress
[deploy.processes.worker] # optional; background job processor
bin = "worker"
scale = { min = 1, max = 3 }
[deploy.services] # declare required backing services
postgres = { required = true } # auto-inferred if using pocopine storage or collab
redis = { required = true } # auto-inferred if jobs or collab present
[deploy.env]
DATABASE_URL = { from = "secret" } # pulled from process env at deploy time
REDIS_URL = { from = "secret" }
LOG_LEVEL = "info" # literal value baked into image
[deploy.render] # host-specific overrides (optional)
owner_id = "tea-..." # Render workspace ID
plan = "starter" # pricing plan
pocopine deploy # prompt for target; build + deploy
pocopine deploy --target fly # name the host explicitly
pocopine deploy --dry-run # print what would happen
pocopine deploy --skip-build # reuse existing image (CI pattern)
pocopine deploy --prod # production environment (suffixes app name)
pocopine deploy auth railway # one-time: store API token
pocopine deploy auth --list # show configured hosts
pocopine deploy doctor # validate Pocopine.toml, probe host APIs
pocopine build # local Rust build; output to target/ + dist/
pocopine build --container # build inside pocopine/build container (reproducible)
DeployAdapter)Every adapter (railway.rs, render.rs, fly.rs) implements:
name() -> &str — adapter identifier (e.g., "railway")mode() -> AdapterMode — Static, Fullstack, or Bothtested_against() -> semver::VersionReq — host API versions this adapter knowsdetect_constraints(spec) -> Vec<Constraint> — pure validation; Refuse halts, Warn/Hint adviserender_config(spec, out) — pure; writes Dockerfile, railway.json, render.yaml to staging dirbuild_artefact(spec) -> Artefact — I/O; invokes docker build, returns OCI image tagdeploy(spec, artefact) -> DeployOutcome — I/O; calls host API, pushes image, triggers deploypost_deploy_hint(spec, outcome) -> Vec<Hint> — pure; returns one-time setup commandsstatus(spec) -> Vec<ProcessStatus> — I/O; query current deploy state per process| Mode | Output | Runtime entrypoint |
|---|---|---|
static | dist/ directory (HTML, JS, CSS, wasm) | host serves files; no app code |
fullstack | OCI image (multi-stage Rust build → distroless) | pocopine-launcher <process> (PID 1 shim) |
# Pocopine.toml
[deploy]
mode = "fullstack"
[deploy.processes.web]
bin = "server"
port = 8080
healthcheck = "/healthz"
scale = { min = 1, max = 5 }
[deploy.processes.worker]
bin = "worker"
scale = { min = 1, max = 3 }
[deploy.services]
postgres = { required = true }
redis = { required = true }
[deploy.env]
DATABASE_URL = { from = "secret" }
REDIS_URL = { from = "secret" }
LOG_LEVEL = "info"
Deploy to three different hosts with identical config:
pocopine deploy --target fly # Fly machines + Fly Postgres + Upstash Redis
pocopine deploy --target railway # Railway services + managed Postgres + managed Redis
pocopine deploy --target render # Render services + managed Postgres + managed Redis
The detect_constraints method gates deployment before building:
fn detect_constraints(&self, spec: &DeploySpec) -> Vec<Constraint> {
let mut out = Vec::new();
if spec.mode == Mode::Static {
out.push(Constraint::Refuse(
"railway adapter is fullstack-only; for static-site mode use `cf-pages`".into(),
));
}
// Scale: Railway holds services warm, so scale.min = 0 floors to 1
for (name, proc) in spec.processes() {
if proc.scale.min == 0 {
out.push(Constraint::Warn(format!(
"process `{name}` scale.min = 0; flooring to 1 (Railway holds services warm)"
)));
}
}
out
}
The launcher resolves process names to binaries at runtime:
fn main() -> ! {
let proc = std::env::args().nth(1)
.or_else(|| std::env::var("POCOPINE_PROCESS").ok())
.expect("usage: pocopine-launcher <process>");
let bin = match proc.as_str() {
"web" => "/usr/local/bin/server", // from [deploy.processes.web] bin = "server"
"worker" => "/usr/local/bin/worker", // from [deploy.processes.worker] bin = "worker"
other => panic!("unknown process: {other}"),
};
exec::Command::new(bin).args(std::env::args().skip(2)).exec();
}
Each host invokes: pocopine-launcher web (for web replicas), pocopine-launcher worker (for background workers).
No vendor code in user crates: unlike RFC 041 (Shuttle), the deploy artefact is an OCI image + portable spec, not vendor-shaped. Never use #[shuttle_*] macros or host-specific entrypoints.
Redis is inferred, not optional: if the build contains #[job] macros or pocopine-collab is in Cargo.toml, redis becomes required = true automatically. Override with redis = { required = false } only if bringing your own Redis.
Collab is not a separate process: the WebSocket handler for collaborative editing rides inside the web process (it's a mounted axum route). Do not declare [deploy.processes.collab].
Secrets must be set in the deploy shell: [deploy.env] KEY = { from = "secret" } means the adapter expects $KEY to be set in the invoking process. At deploy time, the adapter reads it and pushes it to the host's secrets store. Unset secrets cause a Constraint::Refuse before building.
Static mode rejects multiple processes: mode = "static" forbids anything except an optional [deploy.processes.web] with no bin (interpreted as "serve dist/"). Jobs and workers are fullstack-only.
Scale-to-zero semantics vary by host: Fly supports scale.min = 0; Railway and Render floor it to 1 with a warning (they keep services warm). Check the adapter's detect_constraints to see what your target allows.
Process names must normalize safely: web, worker, api-v2, and my_scheduler all work. Names are normalized to env vars: my-api → POCOPINE_PROC_MY_API. Two process names that normalize to the same env var cause a Refuse constraint.
Host-override blocks are optional: [deploy.fly], [deploy.railway], [deploy.render] are for host-specific tweaks (regions, plans, workspace IDs). The portable spec alone is sufficient for basic deploys.
--container is opt-in: pocopine build uses your local Rust toolchain by default (fast iteration). --container builds inside ghcr.io/pocopine/build:<version> for reproducible CI builds. Docker is only required if you use --container.
Generated files are overwritten: Dockerfile, render.yaml, railway.json, and fly.toml are regenerated every deploy from Pocopine.toml. Hand-edits are lost. Use [deploy.<host>] overrides for permanent tweaks, or set generated = "freeze" to stop regenerating and manage the file yourself.
/home/zempare-mambisi/RustProjects/pocopine/rfcs/rfc-080-deploy-contract.md — full specification (process graph, backing services, adapter trait, build container, CLI)crates/pocopine-deploy/ — core trait, spec parsing, shared helperscrates/pocopine-deploy-railway/src/lib.rs — Railway (GraphQL API, project/service/plugin mutations)crates/pocopine-deploy-render/src/lib.rs — Render (REST API, web_service/background_worker types)crates/pocopine-deploy-fly/ — Fly.io (existing Phase 1 adapter; see RFC §10)crates/pocopine-launcher/src/main.rs — process dispatch via POCOPINE_PROC_<NAME> env varscrates/pocopine-deploy/src/common.rs — Dockerfile template rendering, .dockerignore, env collision detectionpocopine-cli's deploy command module orchestrates the pipeline (validate → render_config → build_artefact → deploy → post_deploy_hint)crates/pocopine-deploy/src/config.rs — three-tier lookup (env → Cargo.toml → ~/.pocopine/config.toml)crates/pocopine-deploy/src/credentials.rs — token storage in ~/.pocopine/credentials.toml (0600 perms)