Getting started
From something your agent built to a coworker using it.
Start with what you can build if you are choosing what to make. If you were invited to use something, follow the coworker guide; you do not need any of this.
There are two ways in, and they end in the same place. Most people ask their
coding agent. You can also run the spry command yourself.
The quick way: ask your agent
The full setup for each agent, the tools and what to ask are on using Spryloom from your agent.
1. Add Spryloom to your agent, once.
In Claude Code, the plugin brings the skill and the tools:
/plugin marketplace add spryloom/claude-plugin
/plugin install spryloom@spryloom
In Codex:
codex mcp add spryloom -- npx -y spryloom mcp
In Cursor or another MCP client, add Spryloom to its MCP settings:
{ "mcpServers": { "spryloom": { "command": "npx", "args": ["-y", "spryloom", "mcp"] } } }
The skill is what makes something publish on the first attempt rather than the third: the port an app listens on, the lockfile, the manifest, and whether it should be a page, a page that saves data, or an app. The tools publish, invite people, read logs, roll back, and read a page's saved records.
2. Ask, the way you would ask a colleague.
Make a checklist for our month-end close, and publish it for the finance team.
The agent builds it, tells you whether it chose a page, a page that saves data or an app and why, publishes it, and gives you the address.
3. Sign in, the first time. If you have not signed in, the agent asks for your email the first time you publish. Spryloom emails you a link with a short code; check that the code matches and confirm. There is no password.
4. Invite people. Ask the agent to invite them by email, or say who when you ask it to publish. Each person gets an email, signs in with it, and is in. See the coworker guide for what they see.
Without the plugin, two commands per project do what it does:
spry skill teach the agent in this project how to write apps that publish
claude mcp add spryloom -- spry mcp
It is one sign-in either way: the agent and the terminal act as the same person.
Doing it yourself, with spry
The same steps from a terminal. Publishing, step by step goes through each one in more detail.
1. Install
npm install -g spryloom
One package, one command. Node 20.19 or newer, which you have if you are running a coding agent.
If npm stops with EACCES: permission denied, don't use sudo. Use
npx spryloom in place of spry (it needs nothing installed), or see
Troubleshooting to install it for good.
spry --version
2. Sign in
spry login --email you@yourcompany.com
Your terminal prints a short code and waits. Spryloom emails you a link; open it, check that the page shows the same code, and confirm.
The code matters. A link on its own would approve whichever sign-in it was made for, including one somebody else started — so the page asks you to confirm the sign-in in front of you is yours. If the codes differ, close the page and nothing happens.
There is no password to choose or remember.
3. Publish
From the folder holding your app:
spry publish .
Spryloom reads the folder, builds it, gives it somewhere to run and an address, and waits until it is actually answering before telling you it is live.
Publishing Expense Notes
✓ Runtime created
✓ Database created
✓ Sign-in enabled for yourcompany.com
✓ HTTPS enabled
https://expense-notes.yourcompany-com.spryloom.app
version 1
built in 6s
If the folder has no spryloom.yaml, Spryloom writes one from what it found and
asks you for one thing it cannot work out: a sentence saying what the app does.
spry publish . --description "Tracks expenses that need a second look."
That sentence is not a formality. Your coworkers read it before opening something a colleague made, and it appears in the invitation email and on the app's own page. See the manifest for everything else it declares.
Publishing from somewhere else
The same command takes a zip of the folder, or a GitHub repository:
spry publish ./expense-notes.zip
spry publish github.com/you/expense-notes
spry publish github.com/you/expense-notes@a-branch
Both are read on your machine and become a folder before anything is uploaded,
so everything above applies to them unchanged. For a private repository, set
GITHUB_TOKEN: it is sent to GitHub to fetch the code and reaches Spryloom at
no point.
4. Let somebody use it
First, decide who may open it. A new app is private, which means you and
nobody else. That is deliberate: an app is shut until you say otherwise. Before
inviting anybody, open spryloom.yaml and say who it is for:
access:
visibility: invited # people you name, one at a time
The other options are in who can use your app. Publish again so the change takes effect:
spry publish .
Now invite somebody:
spry invite expense-notes --email ryan@yourcompany.com
Ryan gets an email saying who invited him, what the app is, and what it does. He clicks the link, receives a sign-in link of his own, and is in. He never chooses a password, and you never set one up.
Inviting somebody to an app that is still private is refused, and says so,
rather than sending an invitation to a door that will not open:
"expense-notes" is private, so it is only open to you and its admins.
Nobody was invited and nobody was emailed.
Change access.visibility to "invited" in spryloom.yaml and publish again,
then invite them.
If your app is shared with your whole company, anybody at your domain can open it without being invited at all.
5. Watch what happens
spry apps what you have, and whether it is running
spry logs expense-notes what the app printed
Or open the dashboard in a browser, which shows the same thing plus who has used each app, which versions exist, and anything that needs attention. The dashboard is itself an app published on Spryloom, behind the same sign-in as yours; it reads only what you could read from the terminal.
Publishing a page
A report, a document, or a dashboard of fixed numbers needs no server. Publish the file itself:
spry publish q3-report.html
spry publish team-notes.md
It becomes a page: stored as files and served the moment someone opens it,
behind the same sign-in as an app. Markdown is turned into a readable page. A
folder with an index.html and no package.json publishes as a page too, with
its images, CSS and scripts.
A page is private until you say who it is for. A single file has no
spryloom.yaml to say it in, so say it on the command:
spry publish q3-report.html --visibility invited
spry invite q3-report --email emily@yourcompany.com
--visibility takes the same four values as the manifest, and company needs
--domain. It is for a file or folder with no spryloom.yaml; when there is
one, edit access.visibility there instead.
A Vite or React app with no server is a page too. Publish its folder as usual:
Spryloom runs the build, publishes what it writes to dist, and client-side
routes work.
A page's scripts can load libraries from cdnjs, jsDelivr and unpkg, and fonts from Google Fonts, and can only talk to the page itself.
A page can save data. Declare lists in its spryloom.yaml, and its scripts
save and read records at /~data, each one stamped with who saved it. A
checklist, a sign-off or a sign-up sheet needs nothing more. See
a page that saves data.
When it needs a schedule, email or rules on a server, add a package.json with
a start script and publish again under the same name: it becomes an app at the
same address, with every saved record moved into its database.
Changing it
Publish again. The address stays the same, the data stays where it is, and the version number goes up.
spry publish .
If the new version is wrong:
spry rollback expense-notes
That returns the app to the previous version, which is still there. Rollback changes which code is running. It does not reverse database migrations or repair changed or deleted records, so keep your own export of anything you can't afford to lose.
Writing an app that publishes cleanly
Most failures are decided before you run publish. Four things matter, and your
coding agent should be doing all four for you:
Listen on the port Spryloom gives you. An app that listens on a fixed number builds fine and then serves nothing.
server.listen(process.env.PORT || 3000, '0.0.0.0');
0.0.0.0, not 127.0.0.1. An app bound to loopback cannot be reached from
outside itself.
Read settings from the environment, never from a file you committed. Your database URL and your secrets arrive that way.
Commit a lockfile. Without it, the versions built are not the versions you tested.
Keep what matters in the database. Files written next to the code disappear when the app restarts. See data and secrets.
Next
- Your app's manifest — what you are declaring, and why it is a contract rather than configuration.
- Who can use your app — the four ways to share one, and how your app knows who is knocking.
- Troubleshooting.