small-skill 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -30
- package/SKILL.md +102 -25
- package/bin/install.js +18 -9
- package/package.json +18 -18
- package/references/aws-compute.md +17 -14
- package/references/aws-hosting.md +403 -0
- package/references/aws-production.md +17 -12
- package/references/aws-role.md +12 -6
- package/references/jobs.md +22 -8
package/README.md
CHANGED
|
@@ -1,33 +1,44 @@
|
|
|
1
|
-
# small-skill
|
|
2
|
-
|
|
3
|
-
The agent skill for [small-deploy](https://github.com/yudhisteer/small-deploy):
|
|
4
|
-
teaches Claude Code / Codex to deploy the Python tool it just built behind a
|
|
5
|
-
work-email login in one command — and, when the tool needs AWS, to create and
|
|
6
|
-
maintain the IAM role itself with least privilege.
|
|
7
|
-
|
|
8
|
-
## Install
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
# small-skill
|
|
2
|
+
|
|
3
|
+
The agent skill for [small-deploy](https://github.com/yudhisteer/small-deploy):
|
|
4
|
+
teaches Claude Code / Codex to deploy the Python tool it just built behind a
|
|
5
|
+
work-email login in one command — and, when the tool needs AWS, to create and
|
|
6
|
+
maintain the IAM role itself with least privilege.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
Two packages: the [small-deploy](https://www.npmjs.com/package/small-deploy)
|
|
11
|
+
CLI does the deploying; this skill teaches your agent to drive it.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
npm i -g small-deploy # the CLI (the agent runs `small ...` through it)
|
|
15
|
+
npx small-skill # the skill, into this project's .claude/skills/small
|
|
16
|
+
npx small-skill --global # or into ~/.claude/skills/small for every project
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or, with the CLI already installed: `small skill` installs the skill copy it
|
|
20
|
+
ships with.
|
|
21
|
+
|
|
17
22
|
## What the agent learns
|
|
18
23
|
|
|
24
|
+
- Workspace selection through `small workspaces`, `--workspace`, and
|
|
25
|
+
`SMALL_WORKSPACE`; browser selection is independent of the CLI.
|
|
26
|
+
- `references/aws-hosting.md` — private AWS installation login, workspace
|
|
27
|
+
selection, CPU jobs, configurable app grants and file inputs, plus the hosted
|
|
28
|
+
dashboard's S3 folder approval. Run `small skill` in the project to use the
|
|
29
|
+
installed CLI's matching bundled copy.
|
|
19
30
|
- `small init` → review small.toml → `small deploy` → hand back the URL. Never
|
|
20
|
-
a Dockerfile, never hand-rolled hosting, never bolted-on auth.
|
|
21
|
-
- `references/jobs.md` — on-demand scripts: declare every env read under
|
|
22
|
-
`[inputs]`, write results to `$SMALL_OUTPUTS`, cron schedules.
|
|
23
|
-
- `references/aws-role.md` — the `[aws]` role: created from the trust policy
|
|
24
|
-
the failed deploy prints, scoped to exactly what the code touches, never
|
|
25
|
-
AWS keys in `.env`.
|
|
26
|
-
- `references/aws-compute.md` — when the heavy part truly needs AWS: pick
|
|
27
|
-
Lambda/Fargate/SageMaker/Batch from three plain questions, with the role
|
|
28
|
-
map for each.
|
|
29
|
-
- `references/aws-production.md` — one CDK stack per tool when the MVP grows up.
|
|
30
|
-
|
|
31
|
-
This package is generated from the small-deploy monorepo (`skills/small/`),
|
|
32
|
-
where it is linted against the source and behaviorally evaluated with a
|
|
33
|
-
headless agent before publishing.
|
|
31
|
+
a Dockerfile, never hand-rolled hosting, never bolted-on auth.
|
|
32
|
+
- `references/jobs.md` — on-demand scripts: declare every env read under
|
|
33
|
+
`[inputs]`, write results to `$SMALL_OUTPUTS`, cron schedules.
|
|
34
|
+
- `references/aws-role.md` — the `[aws]` role: created from the trust policy
|
|
35
|
+
the failed deploy prints, scoped to exactly what the code touches, never
|
|
36
|
+
AWS keys in `.env`.
|
|
37
|
+
- `references/aws-compute.md` — when the heavy part truly needs AWS: pick
|
|
38
|
+
Lambda/Fargate/SageMaker/Batch from three plain questions, with the role
|
|
39
|
+
map for each.
|
|
40
|
+
- `references/aws-production.md` — one CDK stack per tool when the MVP grows up.
|
|
41
|
+
|
|
42
|
+
This package is generated from the small-deploy monorepo (`skills/small/`),
|
|
43
|
+
where it is linted against the source and behaviorally evaluated with a
|
|
44
|
+
headless agent before publishing.
|
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: small
|
|
3
|
-
description:
|
|
2
|
+
name: small
|
|
3
|
+
description: Deploys Python tools behind a work-email login and guides customer-AWS job deployment. Use when a user asks to share, deploy, publish, host, or put a Python tool online, wants a team to run it, or finishes an internal tool that exists only on one machine.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# small — share a Python tool in one command
|
|
@@ -8,9 +8,60 @@ description: Deploy the Python tool you just built so colleagues can use it behi
|
|
|
8
8
|
**small IS the deployment path.** Never package, zip, dockerize, write a
|
|
9
9
|
deploy script, or hand-roll hosting for the tool — `small deploy` does all of
|
|
10
10
|
it, including the login wall. If something blocks a small deploy, fix the
|
|
11
|
-
blocker; do not route around small.
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
blocker; do not route around small.
|
|
12
|
+
|
|
13
|
+
**Hosting in the user's AWS account:** if the user asks for this, or
|
|
14
|
+
`small.toml` has `[deploy] target = "aws"`, read `references/aws-hosting.md`
|
|
15
|
+
and follow that flow before running `small init`. That preview keeps source,
|
|
16
|
+
inputs, logs, and outputs in customer AWS and skips hosted model features.
|
|
17
|
+
For a **private Small installation**, install the current `small-deploy` package
|
|
18
|
+
from npm and use the customer's installation URL,
|
|
19
|
+
then `small login --api <installation-url>` for Cognito sign-in. Never use
|
|
20
|
+
the hosted connection setup or an external AWS role for that mode. Private
|
|
21
|
+
installations advertise their supported inputs, constants, grants, and tooltip
|
|
22
|
+
capabilities. Read the AWS hosting reference for the exact syntax and approval
|
|
23
|
+
flow. Image retirement keeps only each app's current successful version;
|
|
24
|
+
older versions must be redeployed before rerunning. Logs and outputs remain.
|
|
25
|
+
For private AWS jobs, supported CLIs accept `[constants]` with text, numbers,
|
|
26
|
+
booleans, and optional tooltips.
|
|
27
|
+
Declare fixed, non-secret values there to show them read-only in Run > Constants.
|
|
28
|
+
Choose only constants from the underlying application's logic that both affect
|
|
29
|
+
its behavior or results and are actually read by the deployed job: detection
|
|
30
|
+
thresholds, confidence cutoffs, cooldowns, rolling windows, or business rules.
|
|
31
|
+
Trace each declaration to the real code that consumes it. A label, model name,
|
|
32
|
+
setting, or other value that the job never reads does not belong in `[constants]`;
|
|
33
|
+
do not add a second display-only copy that can go stale. Read the actual code to
|
|
34
|
+
identify constants; do not invent values or expose every uppercase variable.
|
|
35
|
+
Exclude deployment/adapter plumbing such as `RUN_LIMIT_MB`, `FILE_LIMIT_MB`,
|
|
36
|
+
Fargate settings, timeouts, and internal paths. Explain relevant upload limits in
|
|
37
|
+
the input's `help` or `tooltip` instead. Leave `[constants]` empty or omit it when
|
|
38
|
+
the app has no useful constants to expose.
|
|
39
|
+
Example only—replace the name, value, and explanation with a constant consumed
|
|
40
|
+
by the real job:
|
|
41
|
+
`threshold = { value = 0.85, tooltip = "Minimum score accepted." }` under
|
|
42
|
+
`[constants]`. Run shows the same information icon used for input tooltips.
|
|
43
|
+
Tooltip text is optional, at most 2000 characters; Python still receives only
|
|
44
|
+
the scalar value. The installation must advertise constant-tooltip support.
|
|
45
|
+
The job reads `json.loads(os.environ["SMALL_CONSTANTS"])`; do not duplicate those
|
|
46
|
+
values as hardcoded assignments or editable inputs. Changing them requires deploy.
|
|
47
|
+
The private installation must advertise constants support; see the AWS reference.
|
|
48
|
+
An input's optional `tooltip` adds explanatory text behind an information icon
|
|
49
|
+
beside its label; `help` stays below the input. Use it to explain profile options,
|
|
50
|
+
units or other context. It does not configure the behavior of those options.
|
|
51
|
+
The installation supplies its allowed actions, account, and region; never substitute
|
|
52
|
+
an account from an example. Older private installations need the customer update
|
|
53
|
+
for these capabilities; their existing S3 folder flow remains compatible.
|
|
54
|
+
For an AWS-hosted job reading S3, declare its exact folder with `[aws] s3_read`.
|
|
55
|
+
Deploy requests approval in Small when access changes, waits, and resumes after
|
|
56
|
+
the installer approves. Older connections need one AWS template upgrade first.
|
|
57
|
+
Never grant a shared role broad bucket access or approve for the user without authorization.
|
|
58
|
+
|
|
59
|
+
**Workspaces:** `small workspaces` lists accessible slugs. For a custom
|
|
60
|
+
workspace, pass `--workspace <slug>` on each command or set `SMALL_WORKSPACE`
|
|
61
|
+
for the shell. A browser workspace switch does not select the CLI workspace.
|
|
62
|
+
Use the slug returned by the CLI; never infer it from a display name.
|
|
63
|
+
|
|
64
|
+
When the user asks to share or deploy a Python app you built:
|
|
14
65
|
|
|
15
66
|
1. In the app directory, run:
|
|
16
67
|
|
|
@@ -42,7 +93,9 @@ PyPI, env reads that would be unset, secrets, and the `[aws]` role. Its
|
|
|
42
93
|
one-line `✗`/`⚠` output IS the fix — apply it as printed instead of
|
|
43
94
|
debugging around it.
|
|
44
95
|
|
|
45
|
-
5.
|
|
96
|
+
5. Relay the deploy's closing line. Web apps print a URL — share it. Jobs
|
|
97
|
+
have no URL: the output ends with `✓ built <name> - start it with: small
|
|
98
|
+
run <name>`, and the same run form lives on the dashboard.
|
|
46
99
|
|
|
47
100
|
6. Read the generated runbook back: run `small runbook` (regenerated on every
|
|
48
101
|
deploy; `small runbook --write` saves it as RUNBOOK.md). Tell the user in
|
|
@@ -51,12 +104,21 @@ debugging around it.
|
|
|
51
104
|
Dockerfile, do not suggest hosting options, do not add auth — small already
|
|
52
105
|
put the app behind a work-email login.
|
|
53
106
|
|
|
54
|
-
7. Write AGENT.md (created empty by `small init`, uploaded with every deploy):
|
|
107
|
+
7. Write AGENT.md (created empty by `small init`, uploaded with every deploy):
|
|
55
108
|
things the dashboard's Ask agent should know that the code doesn't say —
|
|
56
109
|
what the app is for, gotchas, who to contact. Two paragraphs, plain
|
|
57
|
-
English. You built the tool, so you write it.
|
|
58
|
-
|
|
59
|
-
|
|
110
|
+
English. You built the tool, so you write it.
|
|
111
|
+
|
|
112
|
+
Before handing the deployment back, verify this checklist:
|
|
113
|
+
|
|
114
|
+
- [ ] `small.toml` matches the real entry, inputs, outputs, and secrets.
|
|
115
|
+
- [ ] `small deploy` completed successfully.
|
|
116
|
+
- [ ] The generated runbook was read back and explained to the user.
|
|
117
|
+
- [ ] `AGENT.md` contains the app-specific context the code does not express.
|
|
118
|
+
|
|
119
|
+
To give someone access when visibility is private, or edit rights:
|
|
120
|
+
|
|
121
|
+
Example only—replace both addresses with the intended members:
|
|
60
122
|
|
|
61
123
|
```
|
|
62
124
|
small share alice@company.com # view
|
|
@@ -65,11 +127,12 @@ small share bob@company.com --edit # can redeploy
|
|
|
65
127
|
|
|
66
128
|
## The code already exists (a script that works locally or on Lambda)
|
|
67
129
|
|
|
68
|
-
Do not rewrite it and do not require it to know about small. Keep the working
|
|
69
|
-
file untouched and add a thin adapter as the entry
|
|
130
|
+
Do not rewrite it and do not require it to know about small. Keep the working
|
|
131
|
+
file untouched and add a thin adapter as the entry. Example only—replace the
|
|
132
|
+
module, inputs, fallback, and output with the real application contract:
|
|
70
133
|
|
|
71
134
|
```python
|
|
72
|
-
# job.py — adapter. Each [inputs]
|
|
135
|
+
# job.py — adapter. Each [inputs] entry in small.toml arrives as an env var:
|
|
73
136
|
# source -> SMALL_INPUT_SOURCE. Files written to $SMALL_OUTPUTS become run outputs.
|
|
74
137
|
import os
|
|
75
138
|
from mytool import main # the user's file, unchanged
|
|
@@ -91,7 +154,7 @@ wiring without reading platform source.
|
|
|
91
154
|
|
|
92
155
|
## The run contract, in one breath
|
|
93
156
|
|
|
94
|
-
`[inputs]` in `small.toml` defines the
|
|
157
|
+
`[inputs]` in `small.toml` defines the inputs once. Every trigger — the
|
|
95
158
|
dashboard Run form, `small run`, `/small run` in Slack, the chat agent's Run
|
|
96
159
|
button, a cron schedule, Run again — delivers the values the same way:
|
|
97
160
|
`SMALL_INPUT_<NAME>` env vars (files land under `$SMALL_INPUTS`). Every file
|
|
@@ -102,6 +165,11 @@ If `small` is not installed: `npm i -g small-deploy`. If not logged in the
|
|
|
102
165
|
deploy fails with "run small login" — have the user run `small login`
|
|
103
166
|
interactively (it emails them a 6-digit code).
|
|
104
167
|
|
|
168
|
+
Builds run on Fly.io remote builders through the `flyctl` binary — no Docker.
|
|
169
|
+
`small deploy` checks for it before touching anything remote and, if missing,
|
|
170
|
+
downloads the official release binary itself (one time, into `~/.small/bin`).
|
|
171
|
+
Only if that auto-install fails does it print a manual install command to run.
|
|
172
|
+
|
|
105
173
|
Apps are served under a path prefix, so use **relative URLs** in HTML
|
|
106
174
|
(`action="inc"`, `href="page"`, `redirect(".")`) — absolute `/paths` break
|
|
107
175
|
behind the proxy.
|
|
@@ -109,7 +177,9 @@ behind the proxy.
|
|
|
109
177
|
If the tool needs to remember anything between requests (counts, submissions,
|
|
110
178
|
history), do not keep it in process memory — the machine is replaced on every
|
|
111
179
|
deploy and state vanishes. Use SQLite (stdlib `sqlite3`, no ORM) in the
|
|
112
|
-
`$SMALL_DATA` directory and add to `small.toml`:
|
|
180
|
+
`$SMALL_DATA` directory and add to `small.toml`:
|
|
181
|
+
|
|
182
|
+
Example only—confirm the storage path and size supported by the deployment:
|
|
113
183
|
|
|
114
184
|
```toml
|
|
115
185
|
[storage]
|
|
@@ -127,19 +197,26 @@ DB = os.path.join(os.environ.get("SMALL_DATA", "."), "tool.db")
|
|
|
127
197
|
(`small init` adds `[storage]` automatically when the entry file imports
|
|
128
198
|
`sqlite3` or references `SMALL_DATA`.)
|
|
129
199
|
|
|
130
|
-
## When to read more
|
|
131
|
-
|
|
132
|
-
-
|
|
200
|
+
## When to read more
|
|
201
|
+
|
|
202
|
+
- Host the entire CPU job in the customer's AWS account → read
|
|
203
|
+
`references/aws-hosting.md`: connect once per workspace, then deploy each
|
|
204
|
+
app through the connection. Use the account and region reported by that
|
|
205
|
+
installation; never copy either from an example.
|
|
206
|
+
- The tool calls AWS (boto3, S3, Lambda, …) → read `references/aws-role.md` before
|
|
133
207
|
touching small.toml: never AWS keys in `.env`, declare an `[aws]` role, and
|
|
134
208
|
create/maintain that role yourself with the user's local AWS credentials.
|
|
135
|
-
- The tool is an on-demand script (`
|
|
136
|
-
declare every non-secret env read under `[inputs]`, save user-facing files
|
|
137
|
-
to `$SMALL_OUTPUTS`.
|
|
138
|
-
-
|
|
139
|
-
|
|
209
|
+
- The tool is an on-demand script (`type = "job"`) → read `references/jobs.md`:
|
|
210
|
+
declare every non-secret env read under `[inputs]`, save user-facing files
|
|
211
|
+
to `$SMALL_OUTPUTS`. If its target is AWS, also read
|
|
212
|
+
`references/aws-hosting.md` directly.
|
|
213
|
+
- The user wants the heavy part "to run on AWS" (big model, GPU, batch volume)
|
|
214
|
+
→ read `references/aws-compute.md` and `references/aws-role.md` directly:
|
|
215
|
+
check small's own machines cover it
|
|
140
216
|
first, then pick Lambda/Fargate/SageMaker/Batch from three plain questions
|
|
141
217
|
and wire it behind the small app.
|
|
142
|
-
- The AWS side outgrows one hand-made resource, or the user says "production"
|
|
143
|
-
→ read `references/aws-production.md
|
|
218
|
+
- The AWS side outgrows one hand-made resource, or the user says "production"
|
|
219
|
+
→ read `references/aws-production.md` and `references/aws-compute.md` directly:
|
|
220
|
+
one CDK stack per tool in `infra/`,
|
|
144
221
|
the whole footprint (compute, pipelines, the `[aws]` role itself) as code,
|
|
145
222
|
`cdk diff` before every deploy.
|
package/bin/install.js
CHANGED
|
@@ -7,14 +7,23 @@ const fs = require('fs');
|
|
|
7
7
|
const os = require('os');
|
|
8
8
|
const path = require('path');
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const
|
|
10
|
+
try {
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
const unsupported = args.find((arg) => arg !== '--global');
|
|
13
|
+
if (unsupported) throw new Error(`unsupported argument ${unsupported}`);
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const src = path.join(__dirname, '..');
|
|
16
|
+
const base = args.includes('--global') ? os.homedir() : process.cwd();
|
|
17
|
+
const dst = path.join(base, '.claude', 'skills', 'small');
|
|
18
|
+
|
|
19
|
+
fs.mkdirSync(path.join(dst, 'references'), { recursive: true });
|
|
20
|
+
fs.copyFileSync(path.join(src, 'SKILL.md'), path.join(dst, 'SKILL.md'));
|
|
21
|
+
for (const f of fs.readdirSync(path.join(src, 'references'))) {
|
|
22
|
+
if (f.endsWith('.md')) fs.copyFileSync(path.join(src, 'references', f), path.join(dst, 'references', f));
|
|
23
|
+
}
|
|
24
|
+
console.log(`✓ small skill installed → ${dst}`);
|
|
25
|
+
console.log('agents now know how to deploy Python tools with small — try: "share this with my team"');
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error(`small-skill: ${error.message}`);
|
|
28
|
+
process.exitCode = 1;
|
|
18
29
|
}
|
|
19
|
-
console.log(`✓ small skill installed → ${dst}`);
|
|
20
|
-
console.log('agents now know how to deploy Python tools with small — try: "share this with my team"');
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "small-skill",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Agent skill for small-deploy: teaches Claude Code/Codex to deploy a Python tool behind a work-email login in one command",
|
|
5
|
-
"bin": {
|
|
6
|
-
"small-skill": "bin/install.js"
|
|
7
|
-
},
|
|
8
|
-
"files": [
|
|
9
|
-
"bin",
|
|
10
|
-
"SKILL.md",
|
|
11
|
-
"references"
|
|
12
|
-
],
|
|
13
|
-
"repository": {
|
|
14
|
-
"type": "git",
|
|
15
|
-
"url": "git+https://github.com/yudhisteer/small-skill.git"
|
|
16
|
-
},
|
|
17
|
-
"license": "MIT"
|
|
18
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "small-skill",
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"description": "Agent skill for small-deploy: teaches Claude Code/Codex to deploy a Python tool behind a work-email login in one command",
|
|
5
|
+
"bin": {
|
|
6
|
+
"small-skill": "bin/install.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"SKILL.md",
|
|
11
|
+
"references"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/yudhisteer/small-skill.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT"
|
|
18
|
+
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Heavy compute on the user's AWS — choosing and wiring it
|
|
2
2
|
|
|
3
|
+
This reference covers a hosted app delegating a heavy operation to AWS. When
|
|
4
|
+
the user wants the entire CPU job hosted in their account, use the AWS hosting
|
|
5
|
+
route in `SKILL.md`; do not replace that choice with hosted compute.
|
|
6
|
+
|
|
3
7
|
Read this when the user wants their script "to run on AWS" — a model too big
|
|
4
8
|
for the app machine, batch inference, GPU, or an existing AWS account they
|
|
5
9
|
must use.
|
|
@@ -7,8 +11,8 @@ must use.
|
|
|
7
11
|
## First: does it need AWS at all?
|
|
8
12
|
|
|
9
13
|
Most "run it on AWS" asks really mean "run it not-on-my-laptop". That is
|
|
10
|
-
`small deploy` (server) or `small run` (job)
|
|
11
|
-
|
|
14
|
+
`small deploy` (server) or `small run` (job), with no customer AWS account or
|
|
15
|
+
extra moving parts. Reach for AWS compute only when the work truly does
|
|
12
16
|
not fit: model or data too large, GPU required, more than a few minutes per
|
|
13
17
|
item at real volume, or the data already lives in their AWS. Say so in one
|
|
14
18
|
sentence and let the user choose.
|
|
@@ -25,14 +29,13 @@ Then decide:
|
|
|
25
29
|
|
|
26
30
|
| Situation | Pick | Why |
|
|
27
31
|
|---|---|---|
|
|
28
|
-
| MVP, bursty, one item
|
|
32
|
+
| MVP, bursty, one item fits Lambda's current execution limits, CPU is fine | **Lambda** (container image) | Zero idle cost and scales to zero |
|
|
29
33
|
| Steady volume, long-running items, still CPU | **Fargate** (ECS service or task) | No 15-min limit, no cold starts at volume |
|
|
30
34
|
| Needs a GPU | **SageMaker endpoint** (or ECS on GPU EC2) | Lambda and Fargate have no GPUs |
|
|
31
35
|
| Huge offline backlog, nobody waiting | **AWS Batch** | Queue it, let it drain cheap |
|
|
32
36
|
|
|
33
|
-
Default to **Lambda** for
|
|
34
|
-
|
|
35
|
-
way). Do not offer the whole table to the user; pick one and say why in one
|
|
37
|
+
Default to **Lambda** for an MVP that fits the service limits verified for the
|
|
38
|
+
customer's region and account. Do not offer the whole table to the user; pick one and say why in one
|
|
36
39
|
sentence ("bursty and small — Lambda, it costs nothing while idle").
|
|
37
40
|
|
|
38
41
|
## Roles — two directions, never mixed
|
|
@@ -40,7 +43,7 @@ sentence ("bursty and small — Lambda, it costs nothing while idle").
|
|
|
40
43
|
Every choice needs IAM on **both sides**. Name them all `small-<app-name>-<purpose>`.
|
|
41
44
|
|
|
42
45
|
**Side 1 — roles the service itself runs as** (create these with the user's
|
|
43
|
-
local credentials
|
|
46
|
+
local credentials after stating what will be created and why):
|
|
44
47
|
|
|
45
48
|
| Compute | Create | It needs |
|
|
46
49
|
|---|---|---|
|
|
@@ -59,23 +62,23 @@ local credentials, per the consent style in references/aws-role.md):
|
|
|
59
62
|
| SageMaker endpoint | `sagemaker:InvokeEndpoint` on that endpoint ARN |
|
|
60
63
|
| Batch | `batch:SubmitJob` on the job queue + job definition |
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
For every new AWS call in code, add one statement for its named resource before
|
|
66
|
+
redeploying; remove statements when the
|
|
64
67
|
call goes. The service's own role never gets what only the app needs, and the
|
|
65
68
|
small role never gets what only the service needs.
|
|
66
69
|
|
|
67
70
|
## Wiring it into small
|
|
68
71
|
|
|
69
72
|
The small app stays the front door — login, Run form, runbook, logs. AWS only
|
|
70
|
-
does the heavy call:
|
|
73
|
+
does the heavy call. Use this checklist:
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
- [ ] Provision with the user's local AWS credentials after one sentence explaining
|
|
76
|
+
what will be created and why.
|
|
74
77
|
For Lambda: build the container image, push to ECR, create the function.
|
|
75
|
-
|
|
78
|
+
- [ ] Let the small app invoke it with boto3 through the `[aws]` role — add exactly
|
|
76
79
|
`lambda:InvokeFunction` on that one function ARN (or the equivalent single
|
|
77
80
|
permission for Fargate/SageMaker/Batch) to the role's inline policy.
|
|
78
|
-
|
|
81
|
+
- [ ] Deploy with `small deploy` — the role verification and review will show the
|
|
79
82
|
AWS call. For a job, results still go to `$SMALL_OUTPUTS`; the Lambda
|
|
80
83
|
returns bytes or writes S3 and the job copies them there.
|
|
81
84
|
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# Host a CPU job in the customer's AWS account
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Deployment checklist](#deployment-checklist)
|
|
6
|
+
- [Private Small installation with Cognito](#private-small-installation-with-cognito)
|
|
7
|
+
- [Hosted dashboard connection](#hosted-dashboard-connection)
|
|
8
|
+
- [Select the workspace and deploy](#select-the-workspace-and-deploy)
|
|
9
|
+
- [Fixed values in Run > Constants](#fixed-values-in-run--constants)
|
|
10
|
+
- [Read an existing S3 folder](#read-an-existing-s3-folder)
|
|
11
|
+
- [MVP limits and data boundary](#mvp-limits-and-data-boundary)
|
|
12
|
+
|
|
13
|
+
## Deployment checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Use the installation URL, account, region, and workspace returned by the customer environment.
|
|
16
|
+
- [ ] Derive inputs, constants, and AWS grants from code the job actually runs.
|
|
17
|
+
- [ ] Validate the source boundary before upload and obtain approval for changed grants.
|
|
18
|
+
- [ ] Deploy, run one representative input, and inspect logs and outputs.
|
|
19
|
+
- [ ] Fix any mismatch at its source, then repeat validation and the representative run.
|
|
20
|
+
|
|
21
|
+
## Private Small installation with Cognito
|
|
22
|
+
|
|
23
|
+
If Small's interface itself is installed in customer AWS, install
|
|
24
|
+
the current `small-deploy` package from npm. Use the installation URL supplied by
|
|
25
|
+
the customer's administrator; this command installs the CLI, not AWS infrastructure.
|
|
26
|
+
Sign in on the machine running the CLI:
|
|
27
|
+
|
|
28
|
+
Command template—replace every angle-bracket placeholder with a value returned
|
|
29
|
+
by the installation or CLI:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
npm install -g small-deploy
|
|
33
|
+
small login --api <installation-url>
|
|
34
|
+
small workspaces
|
|
35
|
+
small deploy --workspace <returned-slug>
|
|
36
|
+
small run <app-name> --workspace <returned-slug> --<input-name> <value>
|
|
37
|
+
small logs <app-name> --workspace <returned-slug>
|
|
38
|
+
small run <app-name> --workspace <returned-slug> --download ./out
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Login opens Cognito and returns to the local CLI with PKCE. The installer
|
|
42
|
+
registers `http://127.0.0.1:8766/auth/callback`; use `--no-browser` when the
|
|
43
|
+
user prefers opening the printed link themselves. Complete sign-in on that
|
|
44
|
+
same computer. For a CLI running over SSH, forward local port `8766` to port
|
|
45
|
+
`8766` on that host before login and keep both commands running until sign-in
|
|
46
|
+
finishes. `--no-browser` alone does not forward the callback. Never request
|
|
47
|
+
passwords, copy browser tokens, or create a user
|
|
48
|
+
to bypass membership. The saved login is bound to this installation's origin.
|
|
49
|
+
Clear a conflicting `SMALL_API` shell override, or set it to the same AWS URL.
|
|
50
|
+
Hosted `SMALL_TOKEN` credentials are ignored for a private login.
|
|
51
|
+
|
|
52
|
+
Use `type = "job"` and `[deploy] target = "aws"` as shown below. Source goes
|
|
53
|
+
directly to customer S3; CodeBuild, ECR, Fargate, CloudWatch, and job output
|
|
54
|
+
remain in that account. The normal Apps list, Run, and Logs show the job.
|
|
55
|
+
The CLI discovers supported inputs, constants, tooltips, and app permissions
|
|
56
|
+
from the installation. When a capability is absent, update the installation;
|
|
57
|
+
installing the CLI alone does not change customer AWS infrastructure.
|
|
58
|
+
|
|
59
|
+
### Images and successful replacements
|
|
60
|
+
|
|
61
|
+
On installations with image retirement, a successful deploy replaces that app's
|
|
62
|
+
current version. Failed or unfinished replacements leave its working version
|
|
63
|
+
available. Older deployment IDs cannot start new runs or uploads: deploy the old
|
|
64
|
+
source again to run it. Small removes replaced build images after their jobs
|
|
65
|
+
finish; run history, logs, and outputs remain. No seven-day rollback window.
|
|
66
|
+
|
|
67
|
+
Generated images upgrade available Debian packages before Python requirements
|
|
68
|
+
and remove Perl last. Rebuild an existing app to receive image changes; an
|
|
69
|
+
installation update does not rebuild deployed app images.
|
|
70
|
+
The generated image deliberately does not support system packages or Perl.
|
|
71
|
+
|
|
72
|
+
### Declare the app's AWS permissions
|
|
73
|
+
|
|
74
|
+
Read the app's actual SDK operations and resource configuration. Declare only
|
|
75
|
+
the actions and resources it needs. Keep `grants` on **one physical line**; the
|
|
76
|
+
small TOML parser supports inline arrays, not multiline arrays or `[[aws.grants]]`.
|
|
77
|
+
Example only—replace the bucket, account, region, function, cluster, and app
|
|
78
|
+
resources with values verified from the customer's application and AWS account:
|
|
79
|
+
|
|
80
|
+
```toml
|
|
81
|
+
[aws]
|
|
82
|
+
grants = [{ action = "s3:PutObject", resource = "arn:aws:s3:::<job-bucket>/jobs/*" }, { action = "s3:GetObject", resource = "arn:aws:s3:::<job-bucket>/reports/*" }, { action = "s3:ListBucket", resource = "arn:aws:s3:::<job-bucket>" }, { action = "lambda:InvokeFunction", resource = "arn:aws:lambda:<installation-region>:<customer-account-id>:function:<launcher-name>" }, { action = "ecs:DescribeTasks", resource = "arn:aws:ecs:<installation-region>:<customer-account-id>:task/<cluster-name>/*" }]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Validate each grant by tracing it to one SDK operation and one resolved customer
|
|
86
|
+
resource. Remove or correct anything without that trace, then repeat until every
|
|
87
|
+
grant is accounted for and no example placeholder or wildcard remains. Deployment
|
|
88
|
+
and owner approval execute the validated plan.
|
|
89
|
+
|
|
90
|
+
`small deploy` requests approval before uploading source. In this private
|
|
91
|
+
installation's **Settings > Connections > AWS > App access**, the owner sees
|
|
92
|
+
each exact action and ARN and chooses **Approve & deploy** or **Cancel**.
|
|
93
|
+
Approval replaces that app's complete grant set. Unchanged grants reuse their
|
|
94
|
+
approval. `grants = []` requests removal; changed grants block new runs of old
|
|
95
|
+
deployments until the new configuration is deployed. Existing running tasks
|
|
96
|
+
remain subject to AWS permission propagation.
|
|
97
|
+
|
|
98
|
+
Never infer the installation's allowed actions from that example. For an action
|
|
99
|
+
outside the installation's advertised allowlist,
|
|
100
|
+
the AWS administrator updates the stack parameter **AppGrantActions**, retaining
|
|
101
|
+
the existing actions and adding the exact action required. This changes the
|
|
102
|
+
installation ceiling; it grants nothing to any app. The agent then retries
|
|
103
|
+
deployment and requests the app's exact resource approval. No new Small release
|
|
104
|
+
is needed for an additional compatible action. Do not edit the stack, broaden
|
|
105
|
+
permissions, or approve a request without the user's authorization.
|
|
106
|
+
|
|
107
|
+
Supported grants have exact action names and same-account resource
|
|
108
|
+
ARNs. S3 accepts exact bucket/object ARNs and trailing folder `/*`; ECS task
|
|
109
|
+
inspection accepts a named cluster's `task/cluster/*`. At most 20 grants per app.
|
|
110
|
+
Wildcard actions, `Resource = "*"`, cross-account resources, IAM/STS and
|
|
111
|
+
organization/account/CloudFormation management are unsupported. AWS validates
|
|
112
|
+
each policy before approval; syntactically valid ARNs do not guarantee an action
|
|
113
|
+
supports that resource type. ListBucket applies to the named bucket's listing.
|
|
114
|
+
The CLI uses the installation's reported region and rejects a different one.
|
|
115
|
+
The boundary also requires AWS to supply `aws:ResourceAccount` for the action;
|
|
116
|
+
operations without that ownership context remain denied.
|
|
117
|
+
|
|
118
|
+
AppGrantActions is an administrator's policy, not a classification of harmless
|
|
119
|
+
operations. PutObject can replace data; InvokeFunction runs with the function's
|
|
120
|
+
existing role; other explicitly enabled actions can change resources. Each
|
|
121
|
+
addition needs deliberate review of those effects. Jobs have no public network
|
|
122
|
+
route. The installation supplies S3, ECR, CloudWatch Logs, Lambda, and ECS
|
|
123
|
+
endpoints; another service may also require a customer-configured VPC endpoint.
|
|
124
|
+
KMS-encrypted data needs the appropriate key permission and network access.
|
|
125
|
+
Do not silently change encryption or add broad permissions to work around it.
|
|
126
|
+
|
|
127
|
+
### File inputs
|
|
128
|
+
|
|
129
|
+
Use the existing Run form's file picker, or a local CLI file path:
|
|
130
|
+
|
|
131
|
+
Example only—replace the input name, accepted extensions, and CLI flag with the
|
|
132
|
+
real job input:
|
|
133
|
+
|
|
134
|
+
```toml
|
|
135
|
+
[inputs]
|
|
136
|
+
event_ids_file = { type = "file", accept = ".txt,.csv", required = true }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
small run <app-name> --workspace <returned-slug> --event-ids-file ./events.txt
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The Python entry receives a local path in `SMALL_INPUT_EVENT_IDS_FILE` (and the
|
|
144
|
+
matching entry in the JSON file referenced by `SMALL_INPUTS`). Read the uploaded
|
|
145
|
+
file normally. Up to five files,
|
|
146
|
+
10 MiB each, go directly to the installation's S3 bucket. Uploads are bound to
|
|
147
|
+
the signed-in user, app, and deployment, verified by checksum, and pinned to an
|
|
148
|
+
S3 version before execution. Never put local source data in the source archive
|
|
149
|
+
as a workaround. Write results to `SMALL_OUTPUTS` as before.
|
|
150
|
+
|
|
151
|
+
### Existing single-folder S3 configuration
|
|
152
|
+
|
|
153
|
+
`[aws] s3_read` remains supported for existing apps. Do not combine it with
|
|
154
|
+
`grants`; switching to `grants` requires explicit approval even for the same
|
|
155
|
+
GetObject folder. Small retires the old role's permissions during that switch.
|
|
156
|
+
|
|
157
|
+
For S3, declare `[aws] s3_read = "s3://<customer-bucket>/<approved-prefix>/"` in
|
|
158
|
+
`small.toml`, then run `small deploy`. When access changes, deployment waits
|
|
159
|
+
before uploading source. The owner opens this **private installation's**
|
|
160
|
+
**Settings > Connections > AWS** and reviews the exact app/folder, then clicks
|
|
161
|
+
**Approve & deploy** or **Cancel**. The CLI resumes after approval; unchanged
|
|
162
|
+
approved folders do not prompt again. No folder inventory appears when idle.
|
|
163
|
+
|
|
164
|
+
With `s3_read`, each app has its own ECS task role. It can get objects only in the approved
|
|
165
|
+
folder, in the installation's account and reported region; it cannot list buckets,
|
|
166
|
+
write, delete, or read another folder. Use `SMALL_S3_BUCKET` and `SMALL_S3_PREFIX`
|
|
167
|
+
in the job, plus a known object key. SSE-KMS buckets need separately scoped KMS
|
|
168
|
+
support and are outside this legacy single-folder flow. Do not add broad KMS permissions.
|
|
169
|
+
|
|
170
|
+
If approval fails while applying, retry that same request in Settings. A
|
|
171
|
+
pending unapproved request can be cancelled. Changing or removing `s3_read`
|
|
172
|
+
requests a new approval; old deployments cannot start new runs with an outdated
|
|
173
|
+
folder. Already running tasks and in-flight requests are not synchronously
|
|
174
|
+
recalled. The permissions handler runs inside this customer's AWS account;
|
|
175
|
+
it uses no external account role. Install the versioned private update once;
|
|
176
|
+
individual folder approvals do not require another CloudFormation update.
|
|
177
|
+
|
|
178
|
+
Use only the customer's installation and AWS account for private BYOC.
|
|
179
|
+
Do not use the hosted Connect AWS flow or add an external trust role for it.
|
|
180
|
+
|
|
181
|
+
## Hosted dashboard connection
|
|
182
|
+
|
|
183
|
+
Use this flow when the user wants the job itself hosted in their AWS account,
|
|
184
|
+
or the project already has `[deploy] target = "aws"`. The workspace has one
|
|
185
|
+
AWS connection and can host multiple CPU-job apps through it.
|
|
186
|
+
|
|
187
|
+
Use the dashboard URL supplied by the user or workspace administrator. Do not
|
|
188
|
+
copy a URL from this reference. Install the current `small-deploy` package and
|
|
189
|
+
run `small skill` in the project to install its matching agent instructions.
|
|
190
|
+
The private installation above uses its own customer-controlled URL.
|
|
191
|
+
|
|
192
|
+
## Connect once
|
|
193
|
+
|
|
194
|
+
1. In the desired workspace, open **Settings → Connections → AWS**.
|
|
195
|
+
2. Enter the customer's 12-digit AWS account ID and first app name.
|
|
196
|
+
3. Click **Connect AWS**. The customer reviews the installation in their AWS
|
|
197
|
+
console and clicks **Create stack**. They need permission to create the
|
|
198
|
+
template's resources and IAM roles. Do not request AWS access keys.
|
|
199
|
+
4. After the stack completes, return to Small and click **Finish connecting**.
|
|
200
|
+
Continue when it says **Connected**. A connected workspace needs no new
|
|
201
|
+
installation for its second or later app.
|
|
202
|
+
|
|
203
|
+
Use the region reported by the connection. A disconnected installation can be reconnected;
|
|
204
|
+
use a new workspace to connect a different AWS account.
|
|
205
|
+
|
|
206
|
+
## Select the workspace and deploy
|
|
207
|
+
|
|
208
|
+
Command template—replace `<small-api-origin>` with the exact origin supplied by
|
|
209
|
+
the user or connection screen:
|
|
210
|
+
|
|
211
|
+
```powershell
|
|
212
|
+
$env:SMALL_API = '<small-api-origin>'
|
|
213
|
+
small workspaces
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
If login is required, have the user run `small login` interactively in that
|
|
217
|
+
shell. Match the intended workspace to its returned slug. Pass that slug with
|
|
218
|
+
`--workspace` on deploy, run, runs, logs, and downloads. `SMALL_WORKSPACE` is
|
|
219
|
+
an optional shell default; the flag overrides it. An invalid slug stops the
|
|
220
|
+
command before it accesses an app. No selection uses the login's email workspace.
|
|
221
|
+
If the CLI says `Server did not select workspace`, stop: that server needs its
|
|
222
|
+
CLI authentication update. Do not retry without the workspace flag or change
|
|
223
|
+
the hosting target.
|
|
224
|
+
|
|
225
|
+
Create or update `small.toml` **before running `small init`** so the AWS target
|
|
226
|
+
is already declared. Do not generate a hosted runbook from this source.
|
|
227
|
+
|
|
228
|
+
Example only—replace the app name, entry, inputs, defaults, and bounds with the
|
|
229
|
+
real job contract:
|
|
230
|
+
|
|
231
|
+
```toml
|
|
232
|
+
name = "<app-name>"
|
|
233
|
+
entry = "<python-entry>"
|
|
234
|
+
type = "job"
|
|
235
|
+
|
|
236
|
+
[deploy]
|
|
237
|
+
target = "aws"
|
|
238
|
+
|
|
239
|
+
[inputs]
|
|
240
|
+
<input-name> = { type = "number", default = <default>, min = <minimum>, max = <maximum> }
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Keep the working Python code; use a thin adapter if needed. The entry reads the
|
|
244
|
+
declared input as `SMALL_INPUT_<INPUT_NAME>` and writes downloadable files under
|
|
245
|
+
`SMALL_OUTPUTS`.
|
|
246
|
+
Use a unique app name with 1–40 lowercase letters, digits, or hyphens.
|
|
247
|
+
|
|
248
|
+
Command template—replace `<slug>`, `<app-name>`, `<input-name>`, and `<value>`
|
|
249
|
+
with values from `small workspaces` and the real `small.toml`:
|
|
250
|
+
|
|
251
|
+
```text
|
|
252
|
+
small deploy --workspace <slug>
|
|
253
|
+
small run <app-name> --workspace <slug> --<input-name> <value>
|
|
254
|
+
small runs <app-name> --workspace <slug>
|
|
255
|
+
small logs <app-name> --workspace <slug>
|
|
256
|
+
small run <app-name> --workspace <slug> --download ./out
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The CLI prints the workspace, AWS account, and region before upload. Source
|
|
260
|
+
goes directly to customer S3, builds run in their account, and the job runs on
|
|
261
|
+
Fargate. Relay the app link printed by deploy. The app appears in the normal
|
|
262
|
+
sidebar; users run it and inspect logs and outputs in the existing app tabs.
|
|
263
|
+
|
|
264
|
+
## Fixed values in Run > Constants
|
|
265
|
+
|
|
266
|
+
Inputs may also include optional `tooltip` text (up to 2000 characters). Small
|
|
267
|
+
shows an information icon beside the label; hover, click or focus it to read the
|
|
268
|
+
explanation. `help` remains below the input. This is explanatory text and does
|
|
269
|
+
not define the Python behavior or change the selected option.
|
|
270
|
+
|
|
271
|
+
Example only—the profiles, thresholds, distances, and cooldowns below illustrate
|
|
272
|
+
tooltip prose; replace them with facts from the real application:
|
|
273
|
+
|
|
274
|
+
```toml
|
|
275
|
+
[inputs]
|
|
276
|
+
profile = { type = "select", default = "prod", options = ["prod", "sensitive"], help = "Choose a detection profile.", tooltip = "Prod: arm elevation 90 degrees, wrist distance 300 mm, cooldown 7 frames. Sensitive: arm elevation 80 degrees, wrist distance 400 mm, cooldown 5 frames." }
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Keep the inline definition on one physical line with the CLI's TOML subset.
|
|
280
|
+
Write plain text; tooltip contents are not interpreted as HTML or executable code.
|
|
281
|
+
|
|
282
|
+
Use the current `small-deploy` package and an installation that advertises
|
|
283
|
+
constants support. Put fixed, non-secret application behavior in `small.toml`:
|
|
284
|
+
|
|
285
|
+
Every declared constant must be consumed by the underlying application and
|
|
286
|
+
affect behavior or result interpretation. Trace it to the code before adding it.
|
|
287
|
+
Do not copy model names or other settings into `[constants]` solely to display
|
|
288
|
+
them; an unused declaration becomes stale. Platform limits and adapter settings
|
|
289
|
+
also stay out of this section.
|
|
290
|
+
|
|
291
|
+
Good example—the Python snippet below consumes this exact value:
|
|
292
|
+
|
|
293
|
+
```toml
|
|
294
|
+
[constants]
|
|
295
|
+
acceptance_threshold = { value = 0.85, tooltip = "Minimum score accepted." }
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
import json
|
|
300
|
+
import os
|
|
301
|
+
|
|
302
|
+
constants = json.loads(os.environ["SMALL_CONSTANTS"])
|
|
303
|
+
acceptance_threshold = constants["acceptance_threshold"]
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Bad example—do not add display-only or platform values that the application
|
|
307
|
+
does not consume:
|
|
308
|
+
|
|
309
|
+
```toml
|
|
310
|
+
[constants]
|
|
311
|
+
model_name = "<display-only-model-name>"
|
|
312
|
+
run_limit_mb = 45
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
The examples establish the boundary: declare a constant only when the real job
|
|
316
|
+
reads it and it affects behavior or result interpretation. Keep inline definitions
|
|
317
|
+
on one physical line. Tooltip text is limited to 2000 characters and counts
|
|
318
|
+
toward the 2 KiB declaration limit. The runtime receives only the scalar value,
|
|
319
|
+
never the tooltip or definition object.
|
|
320
|
+
|
|
321
|
+
Small displays these values read-only under Run > Constants. Redeploy to change
|
|
322
|
+
them; do not offer them as editable `[inputs]` or duplicate the value in Python.
|
|
323
|
+
Every run records its constants snapshot. Existing apps without a declaration
|
|
324
|
+
receive `{}`. For local testing, supply `SMALL_CONSTANTS` with the JSON values
|
|
325
|
+
from the same TOML file. If loading `[constants]` with Python's `tomllib`, unwrap
|
|
326
|
+
each inline definition's `value` before using it as runtime constants.
|
|
327
|
+
|
|
328
|
+
The MVP accepts at most 20 scalar values and 2 KiB total JSON: strings, finite
|
|
329
|
+
numbers, and booleans. Names start with a letter and contain letters, digits or
|
|
330
|
+
underscores, at most 40 characters. Numbers must be in the JavaScript safe range.
|
|
331
|
+
No arrays or nested tables. These are visible configuration values, never secrets.
|
|
332
|
+
Older private installations and shared hosting must be updated/supported before
|
|
333
|
+
deploying a constants declaration; the CLI stops rather than ignoring it.
|
|
334
|
+
|
|
335
|
+
## Read an existing S3 folder
|
|
336
|
+
|
|
337
|
+
Declare one folder in `small.toml`, using a bucket in the connected AWS account
|
|
338
|
+
and the installation's reported region.
|
|
339
|
+
|
|
340
|
+
Example only—replace the bucket and prefix with the approved customer location:
|
|
341
|
+
|
|
342
|
+
```toml
|
|
343
|
+
[aws]
|
|
344
|
+
s3_read = "s3://<customer-bucket>/<approved-prefix>/"
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Use a literal folder, without `*`, `?`, or policy variables. A missing trailing
|
|
348
|
+
slash is added. This grants `GetObject` for explicit keys in that folder, with
|
|
349
|
+
no listing, writes, or KMS decryption grant. Use ordinary SSE-S3 objects for
|
|
350
|
+
this MVP. Add `boto3` to the app's requirements if its code uses that SDK.
|
|
351
|
+
|
|
352
|
+
1. Run `small deploy --workspace <slug>`. If this app needs new or changed
|
|
353
|
+
access, deploy requests approval and waits before uploading source.
|
|
354
|
+
2. In that workspace's **Settings → Connections → AWS → S3 access**, the
|
|
355
|
+
installer reviews the exact folder and clicks **Approve & deploy** or **Cancel**.
|
|
356
|
+
3. The waiting CLI resumes automatically after approval. Cancel stops it without
|
|
357
|
+
uploading source. Subsequent deploys reuse approval until the access changes.
|
|
358
|
+
|
|
359
|
+
For an older installation, Small first shows **One-time AWS connection upgrade**.
|
|
360
|
+
Click **Upgrade in AWS**, select **Replace existing template**, and review the
|
|
361
|
+
generated template. If AWS leaves the URL empty, copy the URL shown in Small
|
|
362
|
+
into **Amazon S3 URL**. Choose **Update stack**, then return and **Check upgrade**.
|
|
363
|
+
The upgrade preserves existing grants; each new folder still requires approval
|
|
364
|
+
in Small. New installations already include this permission handler.
|
|
365
|
+
|
|
366
|
+
The CLI waits for up to 30 minutes; Ctrl+C stops waiting. If it exits, approve
|
|
367
|
+
the request and rerun deploy. A failed AWS permission operation keeps **Retry
|
|
368
|
+
approval** available; do not replace the request with broader access.
|
|
369
|
+
|
|
370
|
+
AWS supplies credentials automatically to this app's dedicated task role.
|
|
371
|
+
The runtime sets `SMALL_S3_BUCKET` and `SMALL_S3_PREFIX` from its approved scope.
|
|
372
|
+
Use `boto3.client("s3").get_object(Bucket=os.environ["SMALL_S3_BUCKET"], Key=key)`
|
|
373
|
+
with a complete key under that prefix. Keep writing generated files under
|
|
374
|
+
`SMALL_OUTPUTS`; the existing output upload/download flow is unchanged.
|
|
375
|
+
|
|
376
|
+
Removing `s3_read` and deploying requests removal of the grant. An older
|
|
377
|
+
deployment whose recorded folder no longer matches approval cannot start.
|
|
378
|
+
Already running work is not stopped. Cancel is unavailable once an approval
|
|
379
|
+
starts applying; retry that exact approval if AWS fails. Do not approve in Small
|
|
380
|
+
or execute an AWS installation upgrade unless the user has authorized that access.
|
|
381
|
+
|
|
382
|
+
`examples/byoc-s3-report` contains a CSV report job and sample file. Upload the
|
|
383
|
+
sample into the chosen folder in customer AWS; set its bucket and input key
|
|
384
|
+
before deploying. Data files still travel directly to AWS.
|
|
385
|
+
|
|
386
|
+
## MVP limits and data boundary
|
|
387
|
+
|
|
388
|
+
- CPU jobs only. Read the connection and deployment output for its region,
|
|
389
|
+
compute size, supported inputs, and enabled capabilities; do not infer them
|
|
390
|
+
from examples in this reference.
|
|
391
|
+
- The connection installer can deploy; workspace members can run and inspect.
|
|
392
|
+
Private app sharing and per-app edit grants are not implemented for AWS jobs.
|
|
393
|
+
- App secrets, extra `[aws] role_arn` grants, system packages, persistent
|
|
394
|
+
volumes, schedules, GPU jobs, and web servers are deferred. Use only input
|
|
395
|
+
types advertised by the installation.
|
|
396
|
+
Do not silently change the hosting target to make an unsupported job deploy.
|
|
397
|
+
- Small receives connection metadata and deployment status. Customer source,
|
|
398
|
+
input values, outputs, and logs travel directly between the client and AWS.
|
|
399
|
+
Do not send them to hosted review, runbook generation, or Coaching. Slack and
|
|
400
|
+
the Coach Agent are not connected to these AWS jobs yet.
|
|
401
|
+
|
|
402
|
+
For a hosted app that only calls an AWS service, or delegates heavy work to AWS,
|
|
403
|
+
return to the direct reference routing in `SKILL.md`; those are separate paths.
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
# Production on AWS — infrastructure as code with CDK
|
|
2
2
|
|
|
3
|
+
For workspace AWS hosting, use the AWS hosting route in `SKILL.md`.
|
|
4
|
+
Its installation already owns the shared infrastructure; do not create a
|
|
5
|
+
second stack per job using the pattern below.
|
|
6
|
+
|
|
3
7
|
Read this when the AWS side of a tool outgrows one hand-made resource: the
|
|
4
8
|
user says "production", a second resource appears (queue, bucket, schedule,
|
|
5
9
|
second function), or they need staging, review, or clean teardown.
|
|
6
10
|
|
|
7
11
|
## When NOT to use this
|
|
8
12
|
|
|
9
|
-
One Lambda behind an MVP does not need a stack
|
|
10
|
-
references/aws-compute.md is fine. Do not gold-plate; promote to CDK when
|
|
13
|
+
One Lambda behind an MVP does not need a stack. Do not gold-plate; promote to CDK when
|
|
11
14
|
repeatability starts paying rent, and say why in one sentence.
|
|
12
15
|
|
|
13
16
|
## The shape
|
|
14
17
|
|
|
15
|
-
One CDK app per tool, in the tool's repo, Python (match the user's language)
|
|
18
|
+
One CDK app per tool, in the tool's repo, Python (match the user's language).
|
|
19
|
+
Illustrative layout—replace `app.py` or `job.py` and the stack name with the
|
|
20
|
+
project's real files and app name:
|
|
16
21
|
|
|
17
22
|
```
|
|
18
23
|
their-tool/
|
|
@@ -30,7 +35,7 @@ Everything AWS the tool touches lives in that one stack:
|
|
|
30
35
|
or a plain task definition for Fargate, Batch job queues for backlogs.
|
|
31
36
|
- **Pipelines**: Step Functions state machines for multi-step flows,
|
|
32
37
|
EventBridge rules for schedules, S3 buckets and queues between stages.
|
|
33
|
-
- **Every role
|
|
38
|
+
- **Every compute role, in the stack**: CDK creates
|
|
34
39
|
the execution/task roles implicitly per construct — accept those defaults,
|
|
35
40
|
then grant by reference instead of writing policy JSON:
|
|
36
41
|
`weightsBucket.grant_read(fn)` (Lambda execution role),
|
|
@@ -40,7 +45,7 @@ Everything AWS the tool touches lives in that one stack:
|
|
|
40
45
|
and per-step invoke grants for you.
|
|
41
46
|
- **The small `[aws]` role too**: define it in the stack — trust policy
|
|
42
47
|
exactly as the failed `small deploy` printed it (principal + org ExternalId),
|
|
43
|
-
then the
|
|
48
|
+
then grant the Small role access to the invoked resources by reference:
|
|
44
49
|
`fn.grant_invoke(small_role)`, `state_machine.grant_start_execution(small_role)`,
|
|
45
50
|
`bucket.grant_read_write(small_role)`. The whole footprint, both sides of
|
|
46
51
|
every role, is then reviewable code — and a removed construct takes its
|
|
@@ -49,20 +54,20 @@ Everything AWS the tool touches lives in that one stack:
|
|
|
49
54
|
Stack outputs (function ARN, bucket name) go into `.env` / `[inputs]` defaults
|
|
50
55
|
— never hard-coded in the script.
|
|
51
56
|
|
|
52
|
-
##
|
|
57
|
+
## Deployment checklist
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
- [ ] Run `cdk bootstrap` once per account and region (tell the user it creates a small
|
|
55
60
|
S3 bucket and roles for deployments).
|
|
56
|
-
|
|
61
|
+
- [ ] Run **`cdk diff` before every `cdk deploy`** — summarize the diff to the user
|
|
57
62
|
in one sentence ("adds one queue, widens nothing") and wait for a yes when
|
|
58
63
|
anything is destroyed or IAM changes.
|
|
59
|
-
|
|
64
|
+
- [ ] When migrating the hand-made MVP, recreate the resource in the stack, cut the
|
|
60
65
|
ARN over in `.env`, verify a run, then delete the hand-made one. Simpler
|
|
61
66
|
and safer than `cdk import` for one or two resources.
|
|
62
|
-
|
|
67
|
+
- [ ] Teardown is `cdk destroy` — mention it exists; it is the reason the stack
|
|
63
68
|
beats console clicking.
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
- [ ] Tag everything (`small:app = <app-name>`) so the user's bill is legible.
|
|
70
|
+
- [ ] Before the first deploy, say what runs idle (Fargate service ≠
|
|
66
71
|
Lambda) in plain money terms.
|
|
67
72
|
|
|
68
73
|
The small app remains the front door — login, Run form, runbook. CDK only
|
package/references/aws-role.md
CHANGED
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Read this when the tool calls AWS (boto3, S3, Lambda, …).
|
|
4
4
|
|
|
5
|
+
This reference covers AWS access from a hosted app. To host the CPU job itself
|
|
6
|
+
in the customer's AWS account, use the AWS hosting route in `SKILL.md` instead.
|
|
7
|
+
|
|
5
8
|
**Never put AWS keys in `.env`.** Declare a role instead:
|
|
6
9
|
|
|
10
|
+
Template—replace each angle-bracket placeholder with values verified from AWS
|
|
11
|
+
and the application:
|
|
12
|
+
|
|
7
13
|
```toml
|
|
8
14
|
[aws]
|
|
9
15
|
role_arn = "arn:aws:iam::<account-id>:role/small-<app-name>"
|
|
@@ -16,24 +22,24 @@ not, it fails with the exact trust policy JSON to paste.
|
|
|
16
22
|
|
|
17
23
|
The user is likely non-technical; their AWS credentials are on this machine
|
|
18
24
|
(`aws sts get-caller-identity` to check; if that fails, ask the user to sign
|
|
19
|
-
in to AWS first).
|
|
25
|
+
in to AWS first). Use this checklist:
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
- [ ] Tell the user in one sentence what you are about to create and why
|
|
22
28
|
("a role that lets small run this tool against your S3 bucket, nothing
|
|
23
29
|
else"). Then:
|
|
24
|
-
|
|
30
|
+
- [ ] Get the account id from `aws sts get-caller-identity`, fill
|
|
25
31
|
`role_arn = "arn:aws:iam::<account>:role/small-<app-name>"` into small.toml,
|
|
26
32
|
and run `small deploy`. It fails and prints the trust policy.
|
|
27
|
-
|
|
33
|
+
- [ ] Create the role with that trust policy **verbatim** (save it to a file,
|
|
28
34
|
`aws iam create-role --role-name small-<app-name>
|
|
29
35
|
--assume-role-policy-document file://trust.json`). Never edit the
|
|
30
36
|
ExternalId — it is the user's org and closes the confused-deputy hole.
|
|
31
|
-
|
|
37
|
+
- [ ] Attach an inline permissions policy for **exactly what the code you wrote
|
|
32
38
|
touches** — you know the actions and resources because you wrote the calls.
|
|
33
39
|
`s3:GetObject` on the one bucket, `lambda:InvokeFunction` on the one
|
|
34
40
|
function. Never `*` actions, never `AdministratorAccess`, never resources
|
|
35
41
|
the tool does not use. (`aws iam put-role-policy`.)
|
|
36
|
-
|
|
42
|
+
- [ ] Run `small deploy` again — it must print `✓ aws role: … (verified)`.
|
|
37
43
|
|
|
38
44
|
**Updating**: when a code change adds a new AWS call, widen the inline policy
|
|
39
45
|
by that one action/resource before redeploying. If a run's log shows
|
package/references/jobs.md
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
# Jobs — inputs and outputs
|
|
2
2
|
|
|
3
|
-
Read this when the tool is a script that runs on demand (`
|
|
3
|
+
Read this when the tool is a script that runs on demand (`type = "job"`).
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
For `[deploy] target = "aws"`, `SKILL.md` routes directly to the additional AWS
|
|
6
|
+
hosting reference.
|
|
7
|
+
Its MVP input types and available triggers are narrower than the hosted
|
|
8
|
+
contract described here.
|
|
9
|
+
|
|
10
|
+
Every non-secret `os.environ` read in a job is an input — declare it in
|
|
11
|
+
`small.toml` instead of leaving it an undeclared env var:
|
|
12
|
+
|
|
13
|
+
Example only—replace the inputs, values, bounds, labels, and file types with the
|
|
14
|
+
real job contract:
|
|
7
15
|
|
|
8
16
|
```toml
|
|
9
17
|
[inputs]
|
|
@@ -16,7 +24,11 @@ annotated = { path = "annotated.jpg", label = "Annotated image" }
|
|
|
16
24
|
|
|
17
25
|
Six types: `file`, `number`, `select`, `date`, `text`, `bool`. Callers pass
|
|
18
26
|
them as flags — `small run app --image ./photo.jpg --threshold 0.7` — and the
|
|
19
|
-
dashboard renders a Run form from the same declaration
|
|
27
|
+
dashboard renders a Run form from the same declaration: a `number` with both
|
|
28
|
+
`min` and `max` draws as a slider with a typed input, `select` a dropdown,
|
|
29
|
+
`bool` a toggle, `file` a dropzone, and `date` a date picker. Text inputs also
|
|
30
|
+
batch: the `+` beside one (or a multi-line paste into it) adds value rows and
|
|
31
|
+
submit starts one run per value with other inputs shared, up to the product limit. Slack (`/small run`),
|
|
20
32
|
the chat agent's Run proposals, cron, and Run again all feed the same
|
|
21
33
|
declaration too: the script receives identical env vars no matter who or what
|
|
22
34
|
started the run. In the script:
|
|
@@ -34,10 +46,12 @@ container: only `$SMALL_OUTPUTS` survives the machine.
|
|
|
34
46
|
|
|
35
47
|
## Schedules
|
|
36
48
|
|
|
37
|
-
A job that should run itself carries a standard
|
|
49
|
+
A job that should run itself carries a standard five-part cron expression, UTC.
|
|
50
|
+
Example only—the schedule below means 09:00 UTC on weekdays; replace it with the
|
|
51
|
+
user's requested schedule:
|
|
38
52
|
|
|
39
53
|
```toml
|
|
40
|
-
|
|
54
|
+
type = "job"
|
|
41
55
|
schedule = "0 9 * * 1-5"
|
|
42
56
|
```
|
|
43
57
|
|
|
@@ -49,8 +63,8 @@ inputs at all** (not even defaults — those are applied by the CLI): a
|
|
|
49
63
|
scheduled job's script must fall back in code,
|
|
50
64
|
`os.environ.get("SMALL_INPUT_THRESHOLD", "0.5")`, or not be scheduled.
|
|
51
65
|
|
|
52
|
-
S3 in/out: declare the URI and destination bucket as `text` inputs and use
|
|
53
|
-
boto3 in the script
|
|
66
|
+
S3 in/out: declare the URI and destination bucket as `text` inputs and use
|
|
67
|
+
boto3 in the script. `SKILL.md` routes AWS callers directly to the role reference.
|
|
54
68
|
|
|
55
69
|
## Existing scripts
|
|
56
70
|
|