atris 2.5.2 → 2.5.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 +10 -0
- package/atris/experiments/README.md +118 -0
- package/atris/experiments/_examples/smoke-keep-revert/README.md +45 -0
- package/atris/experiments/_examples/smoke-keep-revert/candidate.py +8 -0
- package/atris/experiments/_examples/smoke-keep-revert/loop.py +129 -0
- package/atris/experiments/_examples/smoke-keep-revert/measure.py +47 -0
- package/atris/experiments/_examples/smoke-keep-revert/program.md +3 -0
- package/atris/experiments/_examples/smoke-keep-revert/proposals/bad_patch.py +19 -0
- package/atris/experiments/_examples/smoke-keep-revert/proposals/fix_patch.py +22 -0
- package/atris/experiments/_examples/smoke-keep-revert/reset.py +21 -0
- package/atris/experiments/_examples/smoke-keep-revert/results.tsv +5 -0
- package/atris/experiments/_examples/smoke-keep-revert/visual.svg +52 -0
- package/atris/experiments/_fixtures/invalid/BadName/loop.py +1 -0
- package/atris/experiments/_fixtures/invalid/BadName/program.md +3 -0
- package/atris/experiments/_fixtures/invalid/BadName/results.tsv +1 -0
- package/atris/experiments/_fixtures/invalid/bloated-context/loop.py +1 -0
- package/atris/experiments/_fixtures/invalid/bloated-context/measure.py +1 -0
- package/atris/experiments/_fixtures/invalid/bloated-context/program.md +6 -0
- package/atris/experiments/_fixtures/invalid/bloated-context/results.tsv +1 -0
- package/atris/experiments/_fixtures/valid/good-experiment/loop.py +1 -0
- package/atris/experiments/_fixtures/valid/good-experiment/measure.py +1 -0
- package/atris/experiments/_fixtures/valid/good-experiment/program.md +3 -0
- package/atris/experiments/_fixtures/valid/good-experiment/results.tsv +1 -0
- package/atris/experiments/_template/pack/loop.py +3 -0
- package/atris/experiments/_template/pack/measure.py +13 -0
- package/atris/experiments/_template/pack/program.md +3 -0
- package/atris/experiments/_template/pack/reset.py +3 -0
- package/atris/experiments/_template/pack/results.tsv +1 -0
- package/atris/experiments/benchmark_runtime.py +81 -0
- package/atris/experiments/benchmark_validate.py +70 -0
- package/atris/experiments/validate.py +92 -0
- package/atris/policies/atris-design.md +66 -0
- package/atris/skills/README.md +1 -0
- package/atris/skills/apps/SKILL.md +243 -0
- package/atris/skills/autoresearch/SKILL.md +63 -0
- package/atris/skills/create-app/SKILL.md +6 -0
- package/atris/skills/design/SKILL.md +15 -1
- package/atris/skills/drive/SKILL.md +335 -20
- package/atris/skills/ramp/SKILL.md +295 -0
- package/bin/atris.js +76 -5
- package/commands/business.js +132 -0
- package/commands/clean.js +113 -70
- package/commands/console.js +397 -0
- package/commands/experiments.js +216 -0
- package/commands/init.js +4 -0
- package/commands/pull.js +311 -0
- package/commands/push.js +170 -0
- package/commands/run.js +366 -0
- package/commands/status.js +21 -1
- package/package.json +2 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Benchmark the validator against fixed good/bad fixtures."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
ROOT = Path(__file__).resolve().parent
|
|
10
|
+
if str(ROOT) not in sys.path:
|
|
11
|
+
sys.path.insert(0, str(ROOT))
|
|
12
|
+
|
|
13
|
+
from validate import validate_experiment
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
FIXTURES_DIR = ROOT / "_fixtures"
|
|
17
|
+
|
|
18
|
+
CASES = [
|
|
19
|
+
{
|
|
20
|
+
"path": FIXTURES_DIR / "valid" / "good-experiment",
|
|
21
|
+
"expect_ok": True,
|
|
22
|
+
"must_contain": [],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"path": FIXTURES_DIR / "invalid" / "BadName",
|
|
26
|
+
"expect_ok": False,
|
|
27
|
+
"must_contain": ["invalid folder name", "missing required file measure.py"],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"path": FIXTURES_DIR / "invalid" / "bloated-context",
|
|
31
|
+
"expect_ok": False,
|
|
32
|
+
"must_contain": ["program.md too long"],
|
|
33
|
+
},
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def main() -> int:
|
|
38
|
+
passed = 0
|
|
39
|
+
failures = []
|
|
40
|
+
|
|
41
|
+
for case in CASES:
|
|
42
|
+
issues = validate_experiment(case["path"])
|
|
43
|
+
is_ok = not issues
|
|
44
|
+
|
|
45
|
+
if case["expect_ok"] != is_ok:
|
|
46
|
+
failures.append(f"{case['path'].name}: expected ok={case['expect_ok']} got ok={is_ok}")
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
missing = [needle for needle in case["must_contain"] if not any(needle in issue for issue in issues)]
|
|
50
|
+
if missing:
|
|
51
|
+
failures.append(f"{case['path'].name}: missing expected issue(s): {', '.join(missing)}")
|
|
52
|
+
continue
|
|
53
|
+
|
|
54
|
+
passed += 1
|
|
55
|
+
|
|
56
|
+
total = len(CASES)
|
|
57
|
+
score = passed / total if total else 0.0
|
|
58
|
+
print(f"SCORE {score:.4f} ({passed}/{total})")
|
|
59
|
+
|
|
60
|
+
if failures:
|
|
61
|
+
for failure in failures:
|
|
62
|
+
print(f"FAIL {failure}")
|
|
63
|
+
return 1
|
|
64
|
+
|
|
65
|
+
print("PASS benchmark_validate")
|
|
66
|
+
return 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Validate experiments for structure and context hygiene."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
REQUIRED_FILES = ("program.md", "measure.py", "loop.py", "results.tsv")
|
|
11
|
+
MAX_PROGRAM_CHARS = 1200
|
|
12
|
+
MAX_RESULTS_BYTES = 64_000
|
|
13
|
+
SLUG_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def find_experiments(root: Path) -> list[Path]:
|
|
17
|
+
return sorted(
|
|
18
|
+
path
|
|
19
|
+
for path in root.iterdir()
|
|
20
|
+
if path.is_dir() and not path.name.startswith((".", "_"))
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def resolve_experiments(root: Path) -> list[Path]:
|
|
25
|
+
if not root.exists() or not root.is_dir():
|
|
26
|
+
return []
|
|
27
|
+
|
|
28
|
+
# Allow validating a single pack directly, not just a parent directory.
|
|
29
|
+
if any((root / filename).exists() for filename in REQUIRED_FILES):
|
|
30
|
+
return [root]
|
|
31
|
+
|
|
32
|
+
return find_experiments(root)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def validate_experiment(path: Path) -> list[str]:
|
|
36
|
+
issues: list[str] = []
|
|
37
|
+
|
|
38
|
+
if not SLUG_RE.match(path.name):
|
|
39
|
+
issues.append(f"{path.name}: invalid folder name, use lowercase-hyphen slug")
|
|
40
|
+
|
|
41
|
+
for filename in REQUIRED_FILES:
|
|
42
|
+
if not (path / filename).exists():
|
|
43
|
+
issues.append(f"{path.name}: missing required file {filename}")
|
|
44
|
+
|
|
45
|
+
program_path = path / "program.md"
|
|
46
|
+
if program_path.exists():
|
|
47
|
+
size = len(program_path.read_text(encoding="utf-8"))
|
|
48
|
+
if size > MAX_PROGRAM_CHARS:
|
|
49
|
+
issues.append(
|
|
50
|
+
f"{path.name}: program.md too long ({size} chars > {MAX_PROGRAM_CHARS})"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
results_path = path / "results.tsv"
|
|
54
|
+
if results_path.exists():
|
|
55
|
+
size = results_path.stat().st_size
|
|
56
|
+
if size > MAX_RESULTS_BYTES:
|
|
57
|
+
issues.append(
|
|
58
|
+
f"{path.name}: results.tsv too large ({size} bytes > {MAX_RESULTS_BYTES})"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return issues
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def main() -> int:
|
|
65
|
+
parser = argparse.ArgumentParser(description="Validate experiment packs.")
|
|
66
|
+
parser.add_argument("root", nargs="?", default=".", help="Directory containing experiment packs")
|
|
67
|
+
args = parser.parse_args()
|
|
68
|
+
|
|
69
|
+
root = Path(args.root).resolve()
|
|
70
|
+
experiments = resolve_experiments(root)
|
|
71
|
+
if not experiments:
|
|
72
|
+
print("FAIL: no experiments found")
|
|
73
|
+
return 1
|
|
74
|
+
|
|
75
|
+
all_issues: list[str] = []
|
|
76
|
+
for path in experiments:
|
|
77
|
+
all_issues.extend(validate_experiment(path))
|
|
78
|
+
|
|
79
|
+
if all_issues:
|
|
80
|
+
print("FAIL")
|
|
81
|
+
for issue in all_issues:
|
|
82
|
+
print(f"- {issue}")
|
|
83
|
+
return 1
|
|
84
|
+
|
|
85
|
+
print(f"PASS: {len(experiments)} experiment(s) valid")
|
|
86
|
+
for path in experiments:
|
|
87
|
+
print(f"- {path.name}")
|
|
88
|
+
return 0
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if __name__ == "__main__":
|
|
92
|
+
raise SystemExit(main())
|
|
@@ -52,12 +52,43 @@ dark backgrounds are easier to make look good. steal from places you like — li
|
|
|
52
52
|
|
|
53
53
|
**avoid:** static pages with nothing moving, or the opposite — bouncing everything
|
|
54
54
|
|
|
55
|
+
**specific anti-patterns:**
|
|
56
|
+
- cursor-following lines or elements
|
|
57
|
+
- meteor/particle effects shooting across screen
|
|
58
|
+
- buttons that follow the cursor (harder to click, not clever)
|
|
59
|
+
- FAQ/content that breaks if you scroll past before the fade-in finishes
|
|
60
|
+
- animations that swap styles endlessly without purpose (rotating shapes, morphing buttons)
|
|
61
|
+
|
|
55
62
|
**the move:** one well-timed animation beats ten scattered ones. page load with staggered reveals (animation-delay) creates more impact than hover effects on every button.
|
|
56
63
|
|
|
57
64
|
css transitions: 200-300ms, ease-out. that's it.
|
|
58
65
|
|
|
59
66
|
---
|
|
60
67
|
|
|
68
|
+
## hover states
|
|
69
|
+
|
|
70
|
+
**avoid:**
|
|
71
|
+
- elements that fade out or disappear on hover
|
|
72
|
+
- nav items that shift position or slide horizontally on hover
|
|
73
|
+
- arrows/icons that move backwards or vertically on hover
|
|
74
|
+
- hiding critical info or functionality behind hover (hover doesn't exist on mobile)
|
|
75
|
+
|
|
76
|
+
**the move:** hover should make elements feel "lickable" — inviting to click. slightly brighten, scale up (1.02-1.05), or add a subtle glow. the user should feel pulled toward clicking, not confused about what happened.
|
|
77
|
+
|
|
78
|
+
test every hover on mobile. if something only works on hover, it's broken for half your users.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## scroll behavior
|
|
83
|
+
|
|
84
|
+
**avoid:** scrolljacking — never override native browser scroll with custom scroll logic. it feels like "moving through molasses" and users hate it.
|
|
85
|
+
|
|
86
|
+
**the move:** let the browser handle scrolling. if you want scroll-triggered effects, use intersection observer to trigger animations as sections enter the viewport — but don't mess with scroll speed or direction.
|
|
87
|
+
|
|
88
|
+
use the "peeking" technique: let a few pixels of the next section peek above the fold instead of full-screen heroes with "scroll down" arrows. this naturally signals more content below.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
61
92
|
## backgrounds
|
|
62
93
|
|
|
63
94
|
**avoid:** solid white, solid light gray, flat nothing
|
|
@@ -82,12 +113,47 @@ vary your choices. alternate themes. try different directions between projects.
|
|
|
82
113
|
|
|
83
114
|
---
|
|
84
115
|
|
|
116
|
+
## information hierarchy
|
|
117
|
+
|
|
118
|
+
**avoid:** mixing 4-5 competing text styles on one page. labels, headers, subheaders, badges, and body text all fighting for attention.
|
|
119
|
+
|
|
120
|
+
**the move:** pick 2-3 levels max. one dominant style, one supporting, one accent. if you add a new style, ask: does this earn its place or is it clutter?
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## hero section (the H1 test)
|
|
125
|
+
|
|
126
|
+
your hero must answer four questions in seconds:
|
|
127
|
+
1. **what is it?** — clear product description
|
|
128
|
+
2. **who is it for?** — the target user
|
|
129
|
+
3. **to what end?** — why should they care
|
|
130
|
+
4. **what's the CTA?** — one clear next step
|
|
131
|
+
|
|
132
|
+
if a stranger can't answer all four in 5 seconds of looking at your hero, rewrite it.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## assets
|
|
137
|
+
|
|
138
|
+
**avoid:**
|
|
139
|
+
- blurry or low-res screenshots
|
|
140
|
+
- "fake dashboard" mockups with Fisher-Price primary colors (red/yellow/green/blue)
|
|
141
|
+
- non-system emojis used as decoration (lazy AI tell)
|
|
142
|
+
|
|
143
|
+
**the move:** real product screenshots at high resolution. if you don't have a product yet, use a well-designed mockup — but make it sharp and believable.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
85
147
|
## before shipping
|
|
86
148
|
|
|
87
149
|
- can you name the aesthetic in 2-3 words?
|
|
88
150
|
- did you pick a real font, not a default?
|
|
89
151
|
- is there at least one intentional animation?
|
|
90
152
|
- does the background have depth?
|
|
153
|
+
- do hover states feel inviting, not confusing?
|
|
154
|
+
- does scrolling feel native?
|
|
155
|
+
- does the hero pass the H1 test (what/who/why/CTA)?
|
|
156
|
+
- are all screenshots/assets crisp?
|
|
91
157
|
- would a designer immediately clock this as ai-generated?
|
|
92
158
|
|
|
93
159
|
if the last answer is yes, you're not done.
|
package/atris/skills/README.md
CHANGED
|
@@ -27,6 +27,7 @@ cp -r atris/skills/[name] ~/.codex/skills/
|
|
|
27
27
|
|-------|-------------|--------|
|
|
28
28
|
| atris | Workflow enforcement + plan/do/review | `policies/ANTISLOP.md` |
|
|
29
29
|
| autopilot | PRD-driven autonomous execution | — |
|
|
30
|
+
| autoresearch | Bounded keep/revert experiment loops via `atris/experiments/` | — |
|
|
30
31
|
| backend | Backend architecture anti-patterns | `policies/atris-backend.md` |
|
|
31
32
|
| design | Frontend aesthetics policy | `policies/atris-design.md` |
|
|
32
33
|
| calendar | Google Calendar integration via AtrisOS | — |
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apps
|
|
3
|
+
description: View, manage, and trigger Atris apps. Use when user asks about their apps, app status, runs, data, or wants to trigger an app.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags:
|
|
6
|
+
- apps
|
|
7
|
+
- atris
|
|
8
|
+
- management
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Apps
|
|
12
|
+
|
|
13
|
+
View and manage your Atris apps — status, runs, data, secrets, members.
|
|
14
|
+
|
|
15
|
+
## Bootstrap
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)" 2>/dev/null \
|
|
19
|
+
|| python3 -c "import json,os; print(json.load(open(os.path.expanduser('~/.atris/credentials.json')))['token'])" 2>/dev/null)
|
|
20
|
+
if [ -z "$TOKEN" ]; then echo "Not logged in. Run: atris login"; exit 1; fi
|
|
21
|
+
echo "Ready."
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Base URL: `https://api.atris.ai/api/apps`
|
|
25
|
+
|
|
26
|
+
Auth: `-H "Authorization: Bearer $TOKEN"`
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## List My Apps
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
curl -s "https://api.atris.ai/api/apps" \
|
|
34
|
+
-H "Authorization: Bearer $TOKEN"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Returns all apps you own with id, name, slug, description, template, status.
|
|
38
|
+
|
|
39
|
+
### Filter Apps
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Template apps only
|
|
43
|
+
curl -s "https://api.atris.ai/api/apps?filter=template" \
|
|
44
|
+
-H "Authorization: Bearer $TOKEN"
|
|
45
|
+
|
|
46
|
+
# Paid apps
|
|
47
|
+
curl -s "https://api.atris.ai/api/apps?filter=paid" \
|
|
48
|
+
-H "Authorization: Bearer $TOKEN"
|
|
49
|
+
|
|
50
|
+
# Free apps
|
|
51
|
+
curl -s "https://api.atris.ai/api/apps?filter=free" \
|
|
52
|
+
-H "Authorization: Bearer $TOKEN"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## App Details
|
|
58
|
+
|
|
59
|
+
### Get App Status
|
|
60
|
+
```bash
|
|
61
|
+
curl -s "https://api.atris.ai/api/apps/{slug}/status" \
|
|
62
|
+
-H "Authorization: Bearer $TOKEN"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Returns: last run, next run, health, active members.
|
|
66
|
+
|
|
67
|
+
### Get App Runs
|
|
68
|
+
```bash
|
|
69
|
+
curl -s "https://api.atris.ai/api/apps/{slug}/runs?limit=10" \
|
|
70
|
+
-H "Authorization: Bearer $TOKEN"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Get Single Run
|
|
74
|
+
```bash
|
|
75
|
+
curl -s "https://api.atris.ai/api/apps/{slug}/runs/{run_id}" \
|
|
76
|
+
-H "Authorization: Bearer $TOKEN"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## App Data
|
|
82
|
+
|
|
83
|
+
### Read All Data
|
|
84
|
+
```bash
|
|
85
|
+
curl -s "https://api.atris.ai/api/apps/{slug}/data" \
|
|
86
|
+
-H "Authorization: Bearer $TOKEN"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Read Specific Collection
|
|
90
|
+
```bash
|
|
91
|
+
curl -s "https://api.atris.ai/api/apps/{slug}/data/{collection}" \
|
|
92
|
+
-H "Authorization: Bearer $TOKEN"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Push Data In
|
|
96
|
+
```bash
|
|
97
|
+
curl -s -X POST "https://api.atris.ai/api/apps/{slug}/ingest" \
|
|
98
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
99
|
+
-H "Content-Type: application/json" \
|
|
100
|
+
-d '{"collection": "leads", "data": {"name": "Acme", "score": 85}}'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Secrets
|
|
106
|
+
|
|
107
|
+
### List Secret Keys (names + storage tier)
|
|
108
|
+
```bash
|
|
109
|
+
curl -s "https://api.atris.ai/api/apps/{slug}/secrets" \
|
|
110
|
+
-H "Authorization: Bearer $TOKEN"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Returns key names and where they're stored:
|
|
114
|
+
- `"storage_tier": "cloud"` — encrypted in Atris vault
|
|
115
|
+
- `"storage_tier": "local"` — on your machine at `~/.atris/secrets/{slug}/`
|
|
116
|
+
|
|
117
|
+
### Store Secret (cloud)
|
|
118
|
+
```bash
|
|
119
|
+
curl -s -X PUT "https://api.atris.ai/api/apps/{slug}/secrets/{key}" \
|
|
120
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
121
|
+
-H "Content-Type: application/json" \
|
|
122
|
+
-d '{"value": "sk-secret-value"}'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Register Local Secret (manifest only)
|
|
126
|
+
```bash
|
|
127
|
+
curl -s -X POST "https://api.atris.ai/api/apps/{slug}/secrets/{key}/register-local" \
|
|
128
|
+
-H "Authorization: Bearer $TOKEN"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
No value sent. Just tells the web UI "this key exists on my machine."
|
|
132
|
+
|
|
133
|
+
### Delete Secret
|
|
134
|
+
```bash
|
|
135
|
+
curl -s -X DELETE "https://api.atris.ai/api/apps/{slug}/secrets/{key}" \
|
|
136
|
+
-H "Authorization: Bearer $TOKEN"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Members
|
|
142
|
+
|
|
143
|
+
### List App Members
|
|
144
|
+
```bash
|
|
145
|
+
curl -s "https://api.atris.ai/api/apps/{slug}/members" \
|
|
146
|
+
-H "Authorization: Bearer $TOKEN"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Add Member (agent operator)
|
|
150
|
+
```bash
|
|
151
|
+
curl -s -X POST "https://api.atris.ai/api/apps/{slug}/members" \
|
|
152
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
153
|
+
-H "Content-Type: application/json" \
|
|
154
|
+
-d '{"agent_id": "AGENT_ID", "role": "operator"}'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Remove Member
|
|
158
|
+
```bash
|
|
159
|
+
curl -s -X DELETE "https://api.atris.ai/api/apps/{slug}/members/{agent_id}" \
|
|
160
|
+
-H "Authorization: Bearer $TOKEN"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Trigger
|
|
166
|
+
|
|
167
|
+
### Run App Now
|
|
168
|
+
```bash
|
|
169
|
+
curl -s -X POST "https://api.atris.ai/api/apps/{slug}/trigger" \
|
|
170
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
171
|
+
-H "Content-Type: application/json" \
|
|
172
|
+
-d '{"trigger_type": "manual"}'
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## App Manifest (for published apps)
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
curl -s "https://api.atris.ai/api/apps/{slug}/manifest"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
No auth needed. Returns name, description, required secrets, schedule.
|
|
184
|
+
|
|
185
|
+
### Install a Published App
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
curl -s -X POST "https://api.atris.ai/api/apps/{slug}/install" \
|
|
189
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
190
|
+
-H "Content-Type: application/json" \
|
|
191
|
+
-d '{}'
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Workflows
|
|
197
|
+
|
|
198
|
+
### "What apps do I have?"
|
|
199
|
+
1. List apps: `GET /api/apps`
|
|
200
|
+
2. Display: name, slug, template, last run status
|
|
201
|
+
|
|
202
|
+
### "How is my app doing?"
|
|
203
|
+
1. Get status: `GET /api/apps/{slug}/status`
|
|
204
|
+
2. Get recent runs: `GET /api/apps/{slug}/runs?limit=5`
|
|
205
|
+
3. Show: health, last run time, success/failure, output
|
|
206
|
+
|
|
207
|
+
### "Check my app's secrets"
|
|
208
|
+
1. List secrets: `GET /api/apps/{slug}/secrets`
|
|
209
|
+
2. Show each key with storage tier (cloud/local)
|
|
210
|
+
3. If required secrets are missing, tell the user how to add them
|
|
211
|
+
|
|
212
|
+
### "Run my app"
|
|
213
|
+
1. Trigger: `POST /api/apps/{slug}/trigger`
|
|
214
|
+
2. Poll status: `GET /api/apps/{slug}/status` (wait for completion)
|
|
215
|
+
3. Show run result: `GET /api/apps/{slug}/runs?limit=1`
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Quick Reference
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
TOKEN=$(node -e "console.log(require('$HOME/.atris/credentials.json').token)")
|
|
223
|
+
|
|
224
|
+
# List all my apps
|
|
225
|
+
curl -s "https://api.atris.ai/api/apps" -H "Authorization: Bearer $TOKEN"
|
|
226
|
+
|
|
227
|
+
# App status
|
|
228
|
+
curl -s "https://api.atris.ai/api/apps/SLUG/status" -H "Authorization: Bearer $TOKEN"
|
|
229
|
+
|
|
230
|
+
# Recent runs
|
|
231
|
+
curl -s "https://api.atris.ai/api/apps/SLUG/runs?limit=5" -H "Authorization: Bearer $TOKEN"
|
|
232
|
+
|
|
233
|
+
# Trigger a run
|
|
234
|
+
curl -s -X POST "https://api.atris.ai/api/apps/SLUG/trigger" \
|
|
235
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
236
|
+
-d '{"trigger_type":"manual"}'
|
|
237
|
+
|
|
238
|
+
# Read app data
|
|
239
|
+
curl -s "https://api.atris.ai/api/apps/SLUG/data" -H "Authorization: Bearer $TOKEN"
|
|
240
|
+
|
|
241
|
+
# List secrets (with storage tier)
|
|
242
|
+
curl -s "https://api.atris.ai/api/apps/SLUG/secrets" -H "Authorization: Bearer $TOKEN"
|
|
243
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: autoresearch
|
|
3
|
+
description: Karpathy-style keep/revert experiment loop for Atris experiment packs. Use when improving prompts, tools, workers, or bounded repo targets.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags:
|
|
6
|
+
- experiments
|
|
7
|
+
- keep-revert
|
|
8
|
+
- optimization
|
|
9
|
+
- metrics
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Autoresearch Skill
|
|
13
|
+
|
|
14
|
+
Autoresearch means one bounded target, one external metric, one keep/revert loop, one append-only log.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
|
|
18
|
+
- prompt optimization
|
|
19
|
+
- worker routing
|
|
20
|
+
- tool behavior
|
|
21
|
+
- evaluation harnesses
|
|
22
|
+
- any repo-local target that can be measured honestly
|
|
23
|
+
|
|
24
|
+
## Process
|
|
25
|
+
|
|
26
|
+
1. Read `atris/experiments/<slug>/program.md`
|
|
27
|
+
2. Confirm the target is bounded
|
|
28
|
+
3. Run the baseline with `measure.py`
|
|
29
|
+
4. Apply one candidate change
|
|
30
|
+
5. Rerun the metric
|
|
31
|
+
6. Keep only if the score improves
|
|
32
|
+
7. Write the outcome to `results.tsv`
|
|
33
|
+
8. Revert losses
|
|
34
|
+
|
|
35
|
+
## Rules
|
|
36
|
+
|
|
37
|
+
- external metric only
|
|
38
|
+
- no unlogged keeps
|
|
39
|
+
- no broad refactors inside an experiment
|
|
40
|
+
- one experiment pack = one target
|
|
41
|
+
- if variance exists, define the keep margin first
|
|
42
|
+
|
|
43
|
+
## Commands
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
atris experiments init <slug>
|
|
47
|
+
atris experiments validate
|
|
48
|
+
atris experiments benchmark
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Good output
|
|
52
|
+
|
|
53
|
+
- short `program.md`
|
|
54
|
+
- honest `measure.py`
|
|
55
|
+
- deterministic `loop.py`
|
|
56
|
+
- append-only `results.tsv`
|
|
57
|
+
|
|
58
|
+
## Bad output
|
|
59
|
+
|
|
60
|
+
- "felt better"
|
|
61
|
+
- changed three things at once
|
|
62
|
+
- kept a patch without a measured win
|
|
63
|
+
- no reset/revert path
|
|
@@ -104,6 +104,12 @@ unset secret_val
|
|
|
104
104
|
echo "Saved locally."
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
Register the key in the web UI (manifest only — no value sent):
|
|
108
|
+
```bash
|
|
109
|
+
curl -s -X POST "https://api.atris.ai/api/apps/SLUG/secrets/KEY_NAME/register-local" \
|
|
110
|
+
-H "Authorization: Bearer $TOKEN"
|
|
111
|
+
```
|
|
112
|
+
|
|
107
113
|
Verify (key names only, never values):
|
|
108
114
|
```bash
|
|
109
115
|
ls ~/.atris/secrets/SLUG/
|
|
@@ -27,10 +27,20 @@ This skill uses the Atris workflow:
|
|
|
27
27
|
|
|
28
28
|
**Layout:** break the hero + 3 cards + footer template. asymmetry is interesting. dramatic whitespace.
|
|
29
29
|
|
|
30
|
-
**Motion:** one well-timed animation beats ten scattered ones. 200-300ms ease-out.
|
|
30
|
+
**Motion:** one well-timed animation beats ten scattered ones. 200-300ms ease-out. no cursor-following lines, no meteor effects, no buttons that chase the cursor.
|
|
31
|
+
|
|
32
|
+
**Hover:** make elements feel inviting on hover (brighten, subtle scale). never fade out, shift, or hide content behind hover. hover doesn't exist on mobile.
|
|
33
|
+
|
|
34
|
+
**Scroll:** never override native scroll. use "peeking" (show a few px of next section) instead of full-screen hero + scroll arrow.
|
|
35
|
+
|
|
36
|
+
**Hero (H1 test):** must answer in 5 seconds — what is it, who is it for, why care, what's the CTA.
|
|
37
|
+
|
|
38
|
+
**Assets:** high-res screenshots only. no fake dashboards with primary colors. no decorative non-system emojis.
|
|
31
39
|
|
|
32
40
|
**Backgrounds:** add depth. gradients, patterns, mesh effects. flat = boring.
|
|
33
41
|
|
|
42
|
+
**Hierarchy:** 2-3 text levels max. don't mix 5 competing styles.
|
|
43
|
+
|
|
34
44
|
## Before Shipping Checklist
|
|
35
45
|
|
|
36
46
|
Run through `atris/policies/atris-design.md` "before shipping" section:
|
|
@@ -38,6 +48,10 @@ Run through `atris/policies/atris-design.md` "before shipping" section:
|
|
|
38
48
|
- distinctive font, not default?
|
|
39
49
|
- at least one intentional animation?
|
|
40
50
|
- background has depth?
|
|
51
|
+
- hover states feel inviting, not confusing?
|
|
52
|
+
- scrolling feels native?
|
|
53
|
+
- hero passes H1 test (what/who/why/CTA)?
|
|
54
|
+
- all assets crisp?
|
|
41
55
|
- would a designer clock this as ai-generated?
|
|
42
56
|
|
|
43
57
|
## Atris Commands
|