diff --git a/apps/site/.nimbus/routes.json b/apps/site/.nimbus/routes.json
index 56c00c0..19c46d3 100644
--- a/apps/site/.nimbus/routes.json
+++ b/apps/site/.nimbus/routes.json
@@ -10,7 +10,11 @@
"/docs/concepts/security-boundary",
"/docs/connect-agents",
"/docs/deploy",
+ "/docs/deploy/aws",
"/docs/deploy/cloudflare",
+ "/docs/deploy/compose",
+ "/docs/deploy/google-cloud",
+ "/docs/deploy/kubernetes",
"/docs/get-started",
"/docs/mcp",
"/docs/publish",
diff --git a/apps/site/scripts/verify-agent-surfaces.mjs b/apps/site/scripts/verify-agent-surfaces.mjs
index f29c0ca..26c9fa6 100644
--- a/apps/site/scripts/verify-agent-surfaces.mjs
+++ b/apps/site/scripts/verify-agent-surfaces.mjs
@@ -21,6 +21,27 @@ assert.ok(llmsFiles.some((file) => file === join(outputDirectory, "llms.txt")),
const rootLlms = readFileSync(join(outputDirectory, "llms.txt"), "utf8");
assert.match(rootLlms, /^# Artifact Server\n\n> /, "/llms.txt must start with an H1 and project summary blockquote.");
+const homepage = readFileSync(join(outputDirectory, "index.html"), "utf8");
+const installPromptButton = [...homepage.matchAll(/
-
-
+
@@ -205,9 +222,9 @@ When the setup is complete, begin your final response with “Artifact Server is
03
- Review and share feedback.
- Comments stay attached to the exact version and selected content. Share a review link so the next change starts with the full context.
- Comment → Agent → New version
+ Review with your team.
+ Comments stay attached to the exact version and selected content. Share a review link so everyone can discuss the same work.
+ Review link → Team feedback → Next version
@@ -340,10 +357,10 @@ When the setup is complete, begin your final response with “Artifact Server is
try {
await navigator.clipboard.writeText(text);
button.dataset.copied = "true";
- button.setAttribute("aria-label", "Artifact Server setup prompt copied");
+ button.setAttribute("aria-label", button.dataset.copySuccessLabel ?? "Copied");
window.setTimeout(() => {
delete button.dataset.copied;
- button.setAttribute("aria-label", "Copy the Artifact Server setup prompt");
+ button.setAttribute("aria-label", button.dataset.copyLabel ?? "Copy");
}, 1600);
} catch {
// Clipboard unavailable (insecure context or permission denied).
diff --git a/apps/site/src/pages/index.md.ts b/apps/site/src/pages/index.md.ts
index 951bdf0..47bcf23 100644
--- a/apps/site/src/pages/index.md.ts
+++ b/apps/site/src/pages/index.md.ts
@@ -34,6 +34,10 @@ Open source under the GNU Affero General Public License v3.0 (AGPL-3.0-only): us
- [Review with coding agents](https://artifactserver.com/docs/agents/index.md)
- [Deploy for a team](https://artifactserver.com/docs/deploy/index.md)
- [Cloudflare deployment](https://artifactserver.com/docs/deploy/cloudflare/index.md)
+- [Compose deployment](https://artifactserver.com/docs/deploy/compose/index.md)
+- [Kubernetes deployment](https://artifactserver.com/docs/deploy/kubernetes/index.md)
+- [AWS deployment](https://artifactserver.com/docs/deploy/aws/index.md)
+- [Google Cloud deployment](https://artifactserver.com/docs/deploy/google-cloud/index.md)
- [Source](https://github.com/plannotator/artifact-server)
`;
diff --git a/apps/site/src/styles/landing.css b/apps/site/src/styles/landing.css
index 5537f66..193481c 100644
--- a/apps/site/src/styles/landing.css
+++ b/apps/site/src/styles/landing.css
@@ -233,14 +233,13 @@
}
.landing-agent-setup {
- display: flex;
+ display: grid;
max-width: 36rem;
margin-top: 1.25rem;
- gap: 0.75rem;
+ gap: 0.5rem;
}
-.landing-copy-prompt,
-.landing-agent-setup__docs {
+.landing-copy-prompt {
display: flex;
min-height: 3.25rem;
align-items: center;
@@ -258,7 +257,6 @@
.landing-copy-prompt {
min-width: 0;
- flex: 1 1 auto;
gap: 0.875rem;
padding: 0.75rem 0.875rem;
font: inherit;
@@ -286,7 +284,8 @@
}
.landing-copy-prompt__label {
- min-width: 5.75rem;
+ min-width: 0;
+ flex: 1;
font-size: 0.875rem;
font-weight: 650;
text-align: left;
@@ -310,8 +309,7 @@
color: var(--nb-success);
}
-.landing-copy-prompt__icon,
-.landing-agent-setup__docs svg {
+.landing-copy-prompt__icon {
display: grid;
width: 1rem;
height: 1rem;
@@ -319,26 +317,87 @@
place-items: center;
}
-.landing-agent-setup__docs {
- flex: none;
- gap: 0.5rem;
- padding: 0.75rem 1rem;
- font-size: 0.8125rem;
- font-weight: 650;
+.landing-manual-command {
+ display: grid;
+ min-height: 2.75rem;
+ grid-template-columns: minmax(0, 1fr) auto 2rem;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.375rem 0.375rem 0.375rem 0.875rem;
+ border: 1px solid var(--nb-border);
+ background: var(--nb-card);
+ font-family: var(--nb-font-mono);
+ font-size: 0.6875rem;
+}
+
+.landing-manual-command code {
+ min-width: 0;
+ overflow: hidden;
+ color: var(--nb-foreground);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.landing-manual-command a {
+ color: var(--nb-muted-foreground);
+ text-decoration: none;
white-space: nowrap;
+ transition: color 150ms ease;
+}
+
+.landing-copy-icon-button {
+ display: grid;
+ width: 2rem;
+ height: 2rem;
+ place-items: center;
+ border: 1px solid var(--nb-border);
+ background: transparent;
+ color: var(--nb-muted-foreground);
+ cursor: pointer;
+ transition:
+ border-color 150ms ease,
+ color 150ms ease,
+ transform 150ms ease;
+}
+
+.landing-copy-icon-button svg {
+ width: 0.875rem;
+ height: 0.875rem;
+}
+
+.landing-copy-icon-button svg:last-child,
+.landing-copy-icon-button[data-copied] svg:first-child {
+ display: none;
+}
+
+.landing-copy-icon-button[data-copied] {
+ border-color: color-mix(in oklch, var(--nb-success) 70%, var(--nb-border));
+ color: var(--nb-success);
+}
+
+.landing-copy-icon-button[data-copied] svg:last-child {
+ display: block;
}
.landing-copy-prompt:active,
-.landing-agent-setup__docs:active {
+.landing-copy-icon-button:active {
transform: scale(0.96);
}
@media (hover: hover) {
- .landing-copy-prompt:hover,
- .landing-agent-setup__docs:hover {
+ .landing-copy-prompt:hover {
border-color: var(--nb-foreground);
background: var(--nb-muted);
}
+
+ .landing-manual-command a:hover,
+ .landing-copy-icon-button:hover {
+ color: var(--nb-foreground);
+ }
+
+ .landing-copy-icon-button:hover {
+ border-color: var(--nb-foreground);
+ }
}
/* Hero: the full-screen review — artifact canvas plus the open comment panel. */
@@ -1256,18 +1315,20 @@
}
.landing-agent-setup {
- align-items: stretch;
- flex-direction: column;
+ width: 100%;
}
.landing-copy-prompt {
- justify-content: flex-start;
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ justify-items: start;
gap: 0.625rem;
padding-inline: 0.625rem;
}
.landing-agent-setup__marks {
- flex: 1 1 auto;
+ grid-column: 1;
+ grid-row: 1;
gap: 0.25rem;
}
@@ -1278,33 +1339,29 @@
}
.landing-copy-prompt__label {
+ grid-column: 1 / -1;
+ grid-row: 2;
min-width: auto;
font-size: 0.8125rem;
}
.landing-copy-prompt__icon {
+ grid-column: 2;
+ grid-row: 1;
width: 0.875rem;
height: 0.875rem;
}
- .artifact-window {
- height: 30rem;
- box-shadow: 0.75rem 0.75rem 0 color-mix(in oklch, var(--nb-primary) 12%, transparent);
- }
-
- .artifact-window::before {
- display: none;
+ .landing-manual-command {
+ grid-template-columns: minmax(0, 1fr) 2rem;
}
- .artifact-window__body {
- grid-template-columns: 1fr;
- }
-
- .landing-agent-setup__docs {
- align-self: flex-start;
+ .landing-manual-command a {
+ grid-column: 1 / -1;
+ grid-row: 2;
}
- .artifact-canvas {
+ .artifact-window {
display: none;
}
diff --git a/packaging/compose/README.md b/packaging/compose/README.md
index 9c701c3..21d7d64 100644
--- a/packaging/compose/README.md
+++ b/packaging/compose/README.md
@@ -193,11 +193,10 @@ recommended by this production package.
### Configure providers and secrets
-Copy the external-storage environment example and create the two required
-secret files:
+Copy the shared environment example. Then create the two required secret files:
```sh
-cp .env.external-storage.example .env
+cp .env.example .env
install -d -o 1000 -g 1000 -m 0700 /etc/artifact-server
printf 'as_key_key_%s_%s\n' "$(openssl rand -hex 16)" "$(openssl rand -hex 32)" \
> /etc/artifact-server/api-token
diff --git a/project/spec/cloud-deployment-contract.md b/project/spec/cloud-deployment-contract.md
index acca9fe..0f8e2fe 100644
--- a/project/spec/cloud-deployment-contract.md
+++ b/project/spec/cloud-deployment-contract.md
@@ -1,8 +1,8 @@
# Cloud deployment contract
-Status: shared executable contract and AWS and GCP provider packages
-implemented; every target remains gated by its own unfinished real-cloud release
-qualification
+Status: shared executable contract and AWS and GCP provider packages implemented.
+The public AWS and GCP variants passed isolated live qualification. Signed
+release evidence and the AWS private-ingress qualification remain open.
This document is the handoff boundary for the Cloudflare, AWS, and GCP
deployment work. It says exactly what every package receives, what it creates,