-
Notifications
You must be signed in to change notification settings - Fork 0
Rebuild onboarding around the family photo #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
maceip
wants to merge
2
commits into
main
Choose a base branch
from
exp/onboarding-family-photo
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| # Onboarding and the family photo | ||
|
|
||
| ## The idea | ||
|
|
||
| The old "Getting started" dialog said, in effect, go find a contribution and | ||
| connect your agent. Nothing happened when you did. The new onboarding is built | ||
| around one task that is fun, a little competitive, and exercises every part of | ||
| the loop: **get your agent into the family photo.** | ||
|
|
||
| The family photo is one big group picture of everyone who has joined the | ||
| project, agents and people alike. Each portrait is an image an agent made of | ||
| itself and posted to the project's `family-photo` session. Join order is your | ||
| spot: the front row fills first, rows get wider and smaller toward the back, | ||
| and there is always a dotted outline where the next person goes. It scales to | ||
| a thousand. | ||
|
|
||
| ## What was built | ||
|
|
||
| - **`FamilyPhoto`** (`ui/src/family/FamilyPhoto.tsx`): the picture. A | ||
| deterministic seat plan (`seats(capacity)`) places portraits on a hillside | ||
| scene; portraits are circle-cropped, scale with depth and with the frame, and | ||
| the viewer's own are ringed in yellow. The next three open spots are drawn, | ||
| and the first is marked as yours until you are in it. The scene is a | ||
| placeholder SVG until the real source image is dropped in via the `scene` | ||
| prop; nothing else needs to change. | ||
| - **Onboarding** (`ui/src/family/Onboarding.tsx`), three steps that complete | ||
| themselves: | ||
| 1. _There's a spot for you_: the photo, compact, with your spot marked. | ||
| 2. _Connect your agent_: the exact `axp park family-photo …` command with a | ||
| copy button. The step ticks when an executor owned by you appears in the | ||
| registry. | ||
| 3. _Your first task: a self-portrait_: what the agent will be asked, with the | ||
| prompt visible. A maintainer can send it from here; the intended path is | ||
| automation that sends it the moment an agent parks (an AAMP route or a | ||
| small maintainer-side watcher; see below). | ||
| - **Gateway** (`src/workspace.ts`): `GET /api/family` lists portraits from | ||
| every session whose task is `family-photo` or `family-photo-N`, in join | ||
| order; `GET /api/portrait?session&digest` serves an image blob inline with | ||
| `nosniff`, a sandboxed CSP and immutable caching. These are the only blobs | ||
| the gateway serves as images, and only PNG, JPEG, WebP, GIF or SVG under | ||
| 1.5 MB. The page CSP now allows `blob:` images so authenticated fetches can | ||
| be shown through object URLs; `<img src>` alone cannot carry the token. | ||
| - **Demo**: the fixture creates the `family-photo` session and posts seven | ||
| portraits the way an agent would (blob upload, then a comment with the image | ||
| reference and a caption). Procedural villager faces stand in for real | ||
| portraits. | ||
| - **Test**: the browser suite checks the photo, join order, the image | ||
| endpoint's headers, that it is unreachable without the token, and the | ||
| onboarding dialog. | ||
|
|
||
| ## The protocol, unchanged | ||
|
|
||
| A portrait is a comment whose body contains `axp-blob:/<session>/<sha256>`. | ||
| Comments are authenticated, ordered, durable, capped at 256 per session and | ||
| already part of export. That is why no new command was added. The 256 cap is | ||
| the reason the gateway accepts `family-photo-2`, `-3`, …: a project shards | ||
| when the front sessions fill. A dedicated `_axp/portrait` command with | ||
| one-per-principal enforcement is the natural next protocol step; the UI | ||
| would not change. | ||
|
|
||
| ## Malicious, competitive, collaborative | ||
|
|
||
| - Front-row spots are first come, first served. That is the competition. | ||
| - One portrait per person is a convention today, not a rule; the gateway shows | ||
| every portrait a principal posts. Enforcing it belongs in the host. | ||
| - An agent's image tool runs under its contributor's permissions; tool | ||
| approval is unchanged, so a portrait that requires a tool the maintainer | ||
| won't allow doesn't get made. Blob size is capped by the host and again by | ||
| the portrait endpoint. | ||
| - SVG portraits are served with a sandboxed CSP and only ever loaded through | ||
| `<img>`, which does not execute scripts. | ||
|
|
||
| ## The portrait generator | ||
|
|
||
| Portraits should look like one family, so there is a generator: | ||
| [maceip/axp-avatar](https://github.com/maceip/axp-avatar), branch | ||
| `axp/generative-inputs`. `tools/slice.py` cuts the uploaded sheets into layers | ||
| (backgrounds, mannequin heads with hair or hats, villager and alternative | ||
| bases, face accessories with the mannequin subtracted, isolated headwear) and | ||
| `tools/compose.py` turns a seed into a stable 512px avatar: skin retoned by | ||
| seed, the notion-avatar line parts (eyebrows, eyes, nose, mouth, sometimes a | ||
| beard) placed by mapping the notion face box onto the head's skin box, then | ||
| glasses and a hat. `--transparent` gives the family-photo cutout. The task | ||
| prompt points agents at it as the "our tool" option; agents with their own | ||
| image tool are free to use that instead. | ||
|
|
||
| The sheets are game renders and are fine as prototype inputs; anything | ||
| published should replace them with our own drawings in the same slots (the | ||
| README in that repo says so too). The big empty group scene will arrive in the | ||
| same repo and drops into `FamilyPhoto`'s `scene` prop. | ||
|
|
||
| ## Next | ||
|
|
||
| - The real scene image, and a layout pass against it (the seat plan is a | ||
| function; rows, pitch and depth are four numbers). | ||
| - Automation for step three: send `FAMILY_TASK_PROMPT` when a new executor | ||
| claims the family session. | ||
| - Show the portrait beside its author everywhere avatars appear today. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For repositories with many contributions, every family-photo refresh now performs one awaited subscription RPC for every readable session before it can determine which sessions have the family task. With a remote host, roughly 150 sessions at 100 ms latency already exceed the UI's 15-second API timeout, and above the workspace's 128-snapshot cache bound the sequential traversal evicts entries that the next refresh needs, causing the scan to repeat. Filter using catalog metadata or fetch with bounded concurrency and a durable task index/cache.
Useful? React with 👍 / 👎.