diff --git a/README.md b/README.md
index a0d5a5b..e9b618b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,20 @@
+
+
# AgentFormation
-An AWS-native template for private, persistent remote coding environments.
+**Private, persistent coding-agent workspaces in your AWS account.**
+
+
+
+
+
+
+
+
Each approved employee gets one private EC2 runtime and a persistent /workspace—with company SSO and no inbound SSH.
+
+
Quick start · Architecture · Documentation · Security · Contributing
+
+
@@ -18,12 +32,16 @@ password, or authenticator-app setting. An administrator normally assigns a
dedicated AgentFormation access group to the app, and each assigned employee can
create exactly one reviewed coding environment for themself.
+| Company sign-in | Private by default | Persistent by design |
+| --- | --- | --- |
+| IAM Identity Center; no second app password | Private subnet, encrypted EBS, no public IP, and no inbound SSH | `/workspace` and `tmux` keep running after the browser disconnects |
+
> [!IMPORTANT]
> The first complete deployment builds a runtime image and an App Runner service.
> It commonly takes more than 30 minutes. This is normal for the AWS services used
> by the template, not a frozen terminal.
-## What it creates
+## Architecture
```text
assigned employee group
@@ -169,6 +187,17 @@ upload restrictions, and status output. Do not commit a company hostname to the
public repository. Leave `publicUrl` empty to keep using the generated App Runner
address.
+## Documentation
+
+| Guide | Use it for |
+| --- | --- |
+| [Workstation setup](docs/workstation-setup.md) | Installing the AWS CLI and Docker on macOS or Linux, including `amd64` and `arm64` differences |
+| [IAM Identity Center setup](docs/identity-center-setup.md) | Creating the SAML application, attribute mappings, and assigned access group |
+| [Configuration and upgrades](docs/configuration.md) | Choosing settings, moving a deployment, rebuilding images, and applying updates |
+| [Remote CLI sign-in](docs/remote-cli-login.md) | Finishing `localhost` or `127.0.0.1` OAuth callbacks from a browser terminal |
+| [Agent config migration](docs/migrating-local-agent-configs.md) | Moving approved Codex or Claude Code preferences and history into a runtime |
+| [Security model](docs/security-model.md) and [privacy notes](docs/privacy.md) | Understanding trust boundaries, access, stored data, and operational responsibilities |
+
## Daily administration
```bash
diff --git a/assets/agentformation-demo.svg b/assets/agentformation-demo.svg
index 9f3d110..3960d18 100644
--- a/assets/agentformation-demo.svg
+++ b/assets/agentformation-demo.svg
@@ -6,42 +6,31 @@
role="img"
aria-labelledby="title description"
>
-
AgentFormation browser terminal running Codex
+ A laptop using Codex in a remote AgentFormation workspace on AWS
- An animated AgentFormation terminal where a developer asks Codex to add a
- health check, Codex reads and edits files, runs tests, and reports success.
+ An animation showing a laptop opening an encrypted browser session to a
+ private, persistent EC2 workspace in the user's AWS account. The App Runner
+ web app starts an AWS Systems Manager Session Manager stream to a tmux
+ session on private EC2. The laptop and cloud show that same synchronized
+ AgentFormation session while Codex edits a project. The laptop then closes
+ while EC2, encrypted EBS, tmux, and Codex keep running.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -51,36 +40,60 @@
"Liberation Mono", "Courier New", monospace;
}
+ .laptop-lid {
+ animation: laptop-cycle 24s cubic-bezier(0.65, 0, 0.35, 1) infinite;
+ transform-box: view-box;
+ transform-origin: 290px 462px;
+ }
+
+ .browser-connection {
+ animation: browser-connection-cycle 24s ease-in-out infinite;
+ }
+
+ .closed-note,
+ .cloud-continues {
+ animation: show-closed-state 24s ease-in-out infinite;
+ opacity: 0;
+ }
+
+ .connection-line {
+ animation: connection-dashes 1.8s linear infinite;
+ }
+
+ .transfer-dot {
+ animation: transfer 2.4s ease-in-out infinite;
+ }
+
.conversation {
- animation: conversation-cycle 18s ease-in-out -1.5s infinite;
+ animation: conversation-cycle 24s ease-in-out infinite;
}
.prompt-reveal {
- animation: type-prompt 18s steps(32, end) -1.5s infinite;
+ animation: type-prompt 24s steps(32, end) infinite;
}
.thinking {
- animation: show-thinking 18s ease -1.5s infinite;
+ animation: show-thinking 24s ease infinite;
}
.read-step {
- animation: show-read 18s ease -1.5s infinite;
+ animation: show-read 24s ease infinite;
}
.edit-step {
- animation: show-edit 18s ease -1.5s infinite;
+ animation: show-edit 24s ease infinite;
}
.test-step {
- animation: show-test 18s ease -1.5s infinite;
+ animation: show-test 24s ease infinite;
}
.answer {
- animation: show-answer 18s ease -1.5s infinite;
+ animation: show-answer 24s ease infinite;
}
.progress-bar {
- animation: progress-width 18s cubic-bezier(0.2, 0.8, 0.2, 1) -1.5s infinite;
+ animation: progress-width 24s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
}
.activity-dot {
@@ -103,17 +116,80 @@
animation: blink 1s steps(1, end) infinite;
}
- .enter-glow {
- animation: enter-glow 3s ease-in-out infinite;
+ @keyframes laptop-cycle {
+ 0%,
+ 50% {
+ transform: scaleY(1);
+ }
+ 59%,
+ 90% {
+ transform: scaleY(0.035);
+ }
+ 98%,
+ 100% {
+ transform: scaleY(1);
+ }
}
- @keyframes conversation-cycle {
+ @keyframes browser-connection-cycle {
+ 0%,
+ 50% {
+ opacity: 1;
+ }
+ 57%,
+ 92% {
+ opacity: 0;
+ }
+ 98%,
+ 100% {
+ opacity: 1;
+ }
+ }
+
+ @keyframes show-closed-state {
0%,
- 5% {
+ 55% {
+ opacity: 0;
+ transform: translateY(5px);
+ }
+ 61%,
+ 90% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ 96%,
+ 100% {
+ opacity: 0;
+ }
+ }
+
+ @keyframes connection-dashes {
+ to {
+ stroke-dashoffset: -28;
+ }
+ }
+
+ @keyframes transfer {
+ 0%,
+ 100% {
+ opacity: 0;
+ transform: translateX(0);
+ }
+ 15% {
+ opacity: 1;
+ }
+ 75% {
+ opacity: 1;
+ }
+ 90% {
opacity: 0;
+ transform: translateX(120px);
}
- 9%,
- 91% {
+ }
+
+ @keyframes conversation-cycle {
+ 0%,
+ 94% {
opacity: 1;
}
100% {
@@ -123,11 +199,11 @@
@keyframes type-prompt {
0%,
- 5% {
+ 3% {
width: 0;
}
- 18%,
- 91% {
+ 16%,
+ 94% {
width: 520px;
}
100% {
@@ -137,16 +213,16 @@
@keyframes show-thinking {
0%,
- 19% {
+ 15% {
opacity: 0;
transform: translateY(6px);
}
- 23%,
- 38% {
+ 19%,
+ 29% {
opacity: 1;
transform: translateY(0);
}
- 43%,
+ 33%,
100% {
opacity: 0;
transform: translateY(-4px);
@@ -155,12 +231,12 @@
@keyframes show-read {
0%,
- 30% {
+ 24% {
opacity: 0;
transform: translateY(7px);
}
- 34%,
- 91% {
+ 29%,
+ 94% {
opacity: 1;
transform: translateY(0);
}
@@ -171,12 +247,12 @@
@keyframes show-edit {
0%,
- 41% {
+ 38% {
opacity: 0;
transform: translateY(7px);
}
- 45%,
- 91% {
+ 43%,
+ 94% {
opacity: 1;
transform: translateY(0);
}
@@ -187,12 +263,12 @@
@keyframes show-test {
0%,
- 52% {
+ 59% {
opacity: 0;
transform: translateY(7px);
}
- 56%,
- 91% {
+ 64%,
+ 94% {
opacity: 1;
transform: translateY(0);
}
@@ -203,12 +279,12 @@
@keyframes show-answer {
0%,
- 63% {
+ 74% {
opacity: 0;
transform: translateY(8px);
}
- 68%,
- 91% {
+ 79%,
+ 94% {
opacity: 1;
transform: translateY(0);
}
@@ -219,18 +295,18 @@
@keyframes progress-width {
0%,
- 20% {
+ 16% {
width: 0;
opacity: 0;
}
- 24% {
+ 20% {
opacity: 1;
}
- 57% {
+ 65% {
width: 650px;
opacity: 1;
}
- 62%,
+ 70%,
100% {
width: 650px;
opacity: 0;
@@ -270,17 +346,20 @@
}
}
- @keyframes enter-glow {
- 0%,
- 100% {
- opacity: 0.12;
+ @media (prefers-reduced-motion: reduce) {
+ .laptop-lid,
+ .browser-connection,
+ .closed-note,
+ .cloud-continues {
+ animation: none;
+ transform: none;
}
- 50% {
- opacity: 0.28;
+
+ .closed-note,
+ .cloud-continues {
+ display: none;
}
- }
- @media (prefers-reduced-motion: reduce) {
.conversation,
.prompt-reveal,
.read-step,
@@ -288,8 +367,7 @@
.test-step,
.answer,
.activity-dot,
- .cursor,
- .enter-glow {
+ .cursor {
animation: none;
opacity: 1;
transform: none;
@@ -303,14 +381,98 @@
.progress-bar {
display: none;
}
+
+ .connection-line,
+ .transfer-dot {
+ animation: none;
+ }
}
-
-
-
+
+
+
+
+ Your browser attaches to a persistent EC2 workspace
+
+
+ Session Manager reconnects to the same private tmux session.
+
+
+
+ YOUR LAPTOP · BROWSER
+
+
+
+
+
+
+
+
+
+
+
+ Laptop closed
+
+
+
+
+ PRIVATE
+ AWS
+ EC2 RUNTIME
+
+ VPC · PRIVATE SUBNET
+
+
+
+
+
+ tmux + Codex + /workspace
+
+
+ Encrypted EBS · no public IP · no inbound rules
+
+
-
+
+
+
+
+
+
+
+
+ App Runner web app
+
+ SSM Session Manager
+
+
+
+
+ The browser renders the App Runner web app; Systems Manager attaches it to tmux on private EC2.
+
+
+ Laptop closed. EC2, encrypted EBS, tmux, and Codex keep running.
+
+
+
+
+
@@ -413,7 +575,22 @@
-
+
+
+
+
+
+
+
+
+
+
Tab
@@ -421,22 +598,41 @@
Ctrl+C
Ctrl+O
Clear
- New line
- Select text
- Copy
+ New Line
+ Select text
+ Copy
-
+
+
+
-
+
Paste or type here — keystrokes go live…
-
- ↵
- Enter
-
+
+
+
+
+ Enter
+
+