horizon-code 0.1.0
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/assets/python/highlights.scm +137 -0
- package/assets/python/tree-sitter-python.wasm +0 -0
- package/bin/horizon.js +2 -0
- package/package.json +40 -0
- package/src/ai/client.ts +369 -0
- package/src/ai/system-prompt.ts +86 -0
- package/src/app.ts +1454 -0
- package/src/chat/messages.ts +48 -0
- package/src/chat/renderer.ts +243 -0
- package/src/chat/types.ts +18 -0
- package/src/components/code-panel.ts +329 -0
- package/src/components/footer.ts +72 -0
- package/src/components/hooks-panel.ts +224 -0
- package/src/components/input-bar.ts +193 -0
- package/src/components/mode-bar.ts +245 -0
- package/src/components/session-panel.ts +294 -0
- package/src/components/settings-panel.ts +372 -0
- package/src/components/splash.ts +156 -0
- package/src/components/strategy-panel.ts +489 -0
- package/src/components/tab-bar.ts +112 -0
- package/src/components/tutorial-panel.ts +680 -0
- package/src/components/widgets/progress-bar.ts +38 -0
- package/src/components/widgets/sparkline.ts +57 -0
- package/src/hooks/executor.ts +109 -0
- package/src/index.ts +22 -0
- package/src/keys/handler.ts +198 -0
- package/src/platform/auth.ts +36 -0
- package/src/platform/client.ts +159 -0
- package/src/platform/config.ts +121 -0
- package/src/platform/session-sync.ts +158 -0
- package/src/platform/supabase.ts +376 -0
- package/src/platform/sync.ts +149 -0
- package/src/platform/tiers.ts +103 -0
- package/src/platform/tools.ts +163 -0
- package/src/platform/types.ts +86 -0
- package/src/platform/usage.ts +224 -0
- package/src/research/apis.ts +367 -0
- package/src/research/tools.ts +205 -0
- package/src/research/widgets.ts +523 -0
- package/src/state/store.ts +256 -0
- package/src/state/types.ts +109 -0
- package/src/strategy/ascii-chart.ts +74 -0
- package/src/strategy/code-stream.ts +146 -0
- package/src/strategy/dashboard.ts +140 -0
- package/src/strategy/persistence.ts +82 -0
- package/src/strategy/prompts.ts +626 -0
- package/src/strategy/sandbox.ts +137 -0
- package/src/strategy/tools.ts +764 -0
- package/src/strategy/validator.ts +216 -0
- package/src/strategy/widgets.ts +270 -0
- package/src/syntax/setup.ts +54 -0
- package/src/theme/colors.ts +107 -0
- package/src/theme/icons.ts +27 -0
- package/src/util/hyperlink.ts +21 -0
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
// Tutorial panel — split-view panel with tabbed guide content
|
|
2
|
+
// Rendered as markdown with syntax highlighting
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
BoxRenderable,
|
|
6
|
+
TextRenderable,
|
|
7
|
+
ScrollBoxRenderable,
|
|
8
|
+
MarkdownRenderable,
|
|
9
|
+
SyntaxStyle,
|
|
10
|
+
type CliRenderer,
|
|
11
|
+
} from "@opentui/core";
|
|
12
|
+
import { COLORS } from "../theme/colors.ts";
|
|
13
|
+
|
|
14
|
+
const syntaxStyle = SyntaxStyle.create();
|
|
15
|
+
|
|
16
|
+
type TutorialTab = "start" | "overview" | "research" | "strategy" | "portfolio" | "settings" | "commands" | "tips";
|
|
17
|
+
|
|
18
|
+
const TAB_LIST: { id: TutorialTab; label: string }[] = [
|
|
19
|
+
{ id: "start", label: "Start" },
|
|
20
|
+
{ id: "overview", label: "Modes" },
|
|
21
|
+
{ id: "research", label: "Research" },
|
|
22
|
+
{ id: "strategy", label: "Strategy" },
|
|
23
|
+
{ id: "portfolio", label: "Portfolio" },
|
|
24
|
+
{ id: "settings", label: "Config" },
|
|
25
|
+
{ id: "commands", label: "Cmds" },
|
|
26
|
+
{ id: "tips", label: "Tips" },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const CONTENT: Record<TutorialTab, string> = {
|
|
30
|
+
start: `# First Steps
|
|
31
|
+
|
|
32
|
+
Welcome to Horizon. Here's how to get started in 5 minutes.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Step 1: Research a market
|
|
37
|
+
|
|
38
|
+
You're in **Research mode** by default. Just ask:
|
|
39
|
+
|
|
40
|
+
> "What prediction markets are there about bitcoin?"
|
|
41
|
+
|
|
42
|
+
The AI searches **live Polymarket data** and shows results with
|
|
43
|
+
prices, volume, and liquidity. Try:
|
|
44
|
+
|
|
45
|
+
- *"Show me the order book for that first one"*
|
|
46
|
+
- *"What do whales think about this market?"*
|
|
47
|
+
- *"Calculate the EV if I think it's 60% likely"*
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Step 2: Build a strategy
|
|
52
|
+
|
|
53
|
+
Press **Ctrl+R** to switch to **Strategy mode**. Then:
|
|
54
|
+
|
|
55
|
+
> "Build me a market making strategy for this market"
|
|
56
|
+
|
|
57
|
+
The AI researches the market, writes Python code using the
|
|
58
|
+
**Horizon SDK**, validates it, and opens the **code panel** (Ctrl+G)
|
|
59
|
+
showing your strategy with syntax highlighting.
|
|
60
|
+
|
|
61
|
+
Iterate: *"Make the spread tighter"* or *"Add inventory skew"*
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Step 3: Backtest it
|
|
66
|
+
|
|
67
|
+
> "Backtest this strategy"
|
|
68
|
+
|
|
69
|
+
Runs \`hz.backtest()\` with real SDK metrics — Sharpe ratio,
|
|
70
|
+
drawdown, win rate, profit factor, equity curve.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Step 4: Deploy
|
|
75
|
+
|
|
76
|
+
> "Deploy it in paper mode"
|
|
77
|
+
|
|
78
|
+
Your strategy goes live on the Horizon cloud in paper trading mode.
|
|
79
|
+
Switch to **Portfolio mode** (Ctrl+R) to monitor it.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Step 5: Customize
|
|
84
|
+
|
|
85
|
+
- **/settings** — intelligence level, themes, sound, auto-compact
|
|
86
|
+
- **/hooks** — run custom bash commands before/after strategy actions
|
|
87
|
+
- **/env add ALPACA_KEY sk-xxx** — store encrypted API keys for SDK integrations
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Keyboard cheat sheet
|
|
92
|
+
|
|
93
|
+
| Key | What it does |
|
|
94
|
+
|-----|-------------|
|
|
95
|
+
| **Ctrl+R** | Switch mode (research/strategy/portfolio) |
|
|
96
|
+
| **Ctrl+N** | New chat |
|
|
97
|
+
| **Ctrl+L / Ctrl+H** | Switch between open chats |
|
|
98
|
+
| **Ctrl+W** | Close current chat |
|
|
99
|
+
| **Ctrl+E** | Open chat sidebar |
|
|
100
|
+
| **Ctrl+D** | Open bots panel |
|
|
101
|
+
| **Ctrl+G** | Toggle code panel |
|
|
102
|
+
| **Esc** | Stop generation / close panels |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Plans & limits
|
|
107
|
+
|
|
108
|
+
| | **Free** | **Pro** | **Ultra** |
|
|
109
|
+
|---|---------|---------|-----------|
|
|
110
|
+
| Model | Fast | Fast + Standard + Pro | All + Ultra |
|
|
111
|
+
| Tokens/5h | 50K | 500K | 5M |
|
|
112
|
+
| Sentiment | - | Yes | Yes |
|
|
113
|
+
| Knowledge | - | Yes | Yes |
|
|
114
|
+
|
|
115
|
+
Upgrade at **mathematicalcompany.com/pricing**
|
|
116
|
+
`,
|
|
117
|
+
|
|
118
|
+
overview: `# Horizon
|
|
119
|
+
|
|
120
|
+
Horizon is a terminal-native AI trading assistant for **prediction markets**.
|
|
121
|
+
Research, build strategies, and manage your portfolio — all from the terminal.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Quick Start
|
|
126
|
+
|
|
127
|
+
1. **Research** — just ask: *"What's happening with Iran?"*
|
|
128
|
+
2. **Strategy** — switch with **Ctrl+R**: *"Build me a market maker"*
|
|
129
|
+
3. **Portfolio** — switch again: *"Show my deployments"*
|
|
130
|
+
|
|
131
|
+
The AI has **live tools** — it searches real markets, writes real code,
|
|
132
|
+
backtests with real metrics. Never answers from memory.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Three Modes
|
|
137
|
+
|
|
138
|
+
Switch with **Ctrl+R** or \`/mode\`
|
|
139
|
+
|
|
140
|
+
**Research** — 13 live data tools. Search markets, order books,
|
|
141
|
+
whale activity, sentiment, EV calculator, cross-platform comparison.
|
|
142
|
+
|
|
143
|
+
**Strategy** — Full coding partner. Writes Python with the Horizon SDK,
|
|
144
|
+
validates, backtests with \`hz.backtest()\`, runs locally in sandbox,
|
|
145
|
+
deploys to the cloud. Code panel shows syntax-highlighted source.
|
|
146
|
+
|
|
147
|
+
**Portfolio** — Monitor live deployments. P&L, positions, orders,
|
|
148
|
+
drawdown. Start, stop, restart from the bots panel.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Layout
|
|
153
|
+
|
|
154
|
+
| Area | Key | What it does |
|
|
155
|
+
|------|-----|-------------|
|
|
156
|
+
| **Chat** | — | Left side, talk to the AI |
|
|
157
|
+
| **Code panel** | Ctrl+G | Right side, strategy code + logs |
|
|
158
|
+
| **Sessions** | Ctrl+E | Left overlay, manage chats |
|
|
159
|
+
| **Bots** | Ctrl+D | Right overlay, monitor strategies |
|
|
160
|
+
| **Tutorial** | /tutorial | This guide |
|
|
161
|
+
| **Settings** | /settings | Configuration |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Authentication
|
|
166
|
+
|
|
167
|
+
\`/login\` opens your browser — sign in with **Google** or email.
|
|
168
|
+
Sessions, strategies, and settings sync across devices.
|
|
169
|
+
`,
|
|
170
|
+
|
|
171
|
+
research: `# Research Mode
|
|
172
|
+
|
|
173
|
+
The AI has 13 tools that fetch **live data** from Polymarket, Kalshi,
|
|
174
|
+
and the web. It never answers from memory — always calls tools.
|
|
175
|
+
|
|
176
|
+
## Market Discovery
|
|
177
|
+
|
|
178
|
+
Ask about any topic and the AI searches 200+ active markets:
|
|
179
|
+
|
|
180
|
+
- "What's happening with Iran?"
|
|
181
|
+
- "Show me crypto markets"
|
|
182
|
+
- "Any sports betting markets?"
|
|
183
|
+
|
|
184
|
+
## Deep Analysis
|
|
185
|
+
|
|
186
|
+
Once you find a market, dig deeper:
|
|
187
|
+
|
|
188
|
+
- **Event detail** — sub-markets, prices, spreads, volume, sparkline
|
|
189
|
+
- **Order book** — bid/ask depth with visual bars
|
|
190
|
+
- **Price history** — sparkline charts at any interval (1h to max)
|
|
191
|
+
- **Whale tracker** — large trades, smart money flow direction
|
|
192
|
+
- **Sentiment** — news analysis with bull/bear gauge
|
|
193
|
+
- **Volatility** — realized vol, regime detection (high/normal/low)
|
|
194
|
+
|
|
195
|
+
## Quantitative Tools
|
|
196
|
+
|
|
197
|
+
- **EV Calculator** — expected value, edge, Kelly criterion sizing
|
|
198
|
+
- **Probability** — joint and conditional probabilities between markets
|
|
199
|
+
- **Cross-platform** — compare Polymarket vs Kalshi prices for arbitrage
|
|
200
|
+
|
|
201
|
+
## Tool Chaining
|
|
202
|
+
|
|
203
|
+
The AI remembers market slugs from previous results. Say "tell me more
|
|
204
|
+
about the first one" and it uses the slug without re-searching.
|
|
205
|
+
|
|
206
|
+
## Widgets
|
|
207
|
+
|
|
208
|
+
Tool results render as rich terminal widgets — not raw text. Order
|
|
209
|
+
books show depth bars, sparklines show price trends, sentiment shows
|
|
210
|
+
a gauge. The AI adds 1-2 sentences of insight after each widget.
|
|
211
|
+
`,
|
|
212
|
+
|
|
213
|
+
strategy: `# Strategy Mode
|
|
214
|
+
|
|
215
|
+
Build trading strategies with the Horizon SDK. The AI is a coding
|
|
216
|
+
partner — it researches markets, writes code, validates, backtests,
|
|
217
|
+
runs locally, and deploys to the cloud.
|
|
218
|
+
|
|
219
|
+
## Workflow
|
|
220
|
+
|
|
221
|
+
1. **Describe your idea** — "build a market maker for bitcoin"
|
|
222
|
+
2. **AI researches** — checks real spreads, volume, liquidity
|
|
223
|
+
3. **AI proposes code** — complete Python with hz.run()
|
|
224
|
+
4. **Code panel opens** — shows the code with syntax highlighting
|
|
225
|
+
5. **Iterate** — "make the spread tighter", "add a stop loss"
|
|
226
|
+
6. **Backtest** — "backtest it" runs real hz.backtest()
|
|
227
|
+
7. **Run locally** — "run it" executes in paper mode sandbox
|
|
228
|
+
8. **Deploy** — "deploy it" pushes to Horizon cloud
|
|
229
|
+
|
|
230
|
+
## Code Panel (Ctrl+G)
|
|
231
|
+
|
|
232
|
+
Three tabs:
|
|
233
|
+
- **Code** — strategy source with Python highlighting
|
|
234
|
+
- **Logs** — stdout/stderr from run_strategy
|
|
235
|
+
- **Dashboard** — HTML source from spawn_dashboard
|
|
236
|
+
|
|
237
|
+
Switch tabs with Ctrl+1, Ctrl+2, Ctrl+3.
|
|
238
|
+
|
|
239
|
+
## Tools
|
|
240
|
+
|
|
241
|
+
Strategy code is generated by writing \`\`\`python code fences.
|
|
242
|
+
Code streams into the panel in real-time as the AI writes it.
|
|
243
|
+
|
|
244
|
+
| Tool | Purpose |
|
|
245
|
+
|------|---------|
|
|
246
|
+
| edit_strategy | Find-and-replace for small changes |
|
|
247
|
+
| validate_strategy | Check against SDK sandbox rules |
|
|
248
|
+
| backtest_strategy | Run hz.backtest() with real metrics |
|
|
249
|
+
| run_strategy | Execute locally in paper mode |
|
|
250
|
+
| read_logs | Check process output |
|
|
251
|
+
| save_strategy | Push to Horizon platform |
|
|
252
|
+
| lookup_sdk_docs | Fetch advanced SDK docs |
|
|
253
|
+
| polymarket_data | Search real markets |
|
|
254
|
+
| run_command | Shell commands (pip install, etc.) |
|
|
255
|
+
| spawn_dashboard | Serve custom HTML dashboard |
|
|
256
|
+
|
|
257
|
+
## The Code
|
|
258
|
+
|
|
259
|
+
Strategies are single Python files using the Horizon SDK:
|
|
260
|
+
|
|
261
|
+
\`\`\`python
|
|
262
|
+
import horizon as hz
|
|
263
|
+
|
|
264
|
+
def fair_value(ctx):
|
|
265
|
+
feed = ctx.feeds.get("mid")
|
|
266
|
+
if not feed or feed.is_stale(30):
|
|
267
|
+
return None
|
|
268
|
+
return feed.price
|
|
269
|
+
|
|
270
|
+
def quoter(ctx, fair):
|
|
271
|
+
if fair is None:
|
|
272
|
+
return []
|
|
273
|
+
return hz.quotes(fair, spread=0.06, size=5)
|
|
274
|
+
|
|
275
|
+
hz.run(
|
|
276
|
+
name="MyStrategy",
|
|
277
|
+
exchange=hz.Polymarket(),
|
|
278
|
+
markets=["market-slug"],
|
|
279
|
+
feeds={"mid": hz.PolymarketBook("market-slug")},
|
|
280
|
+
pipeline=[fair_value, quoter],
|
|
281
|
+
risk=hz.Risk(max_position=100),
|
|
282
|
+
mode="paper",
|
|
283
|
+
)
|
|
284
|
+
\`\`\`
|
|
285
|
+
|
|
286
|
+
## File Persistence
|
|
287
|
+
|
|
288
|
+
Strategies auto-save to ~/.horizon/strategies/ on every change.
|
|
289
|
+
Use \`/strategies\` to list, \`/load <name>\` to load.
|
|
290
|
+
`,
|
|
291
|
+
|
|
292
|
+
portfolio: `# Portfolio Mode
|
|
293
|
+
|
|
294
|
+
Monitor and manage your live deployments.
|
|
295
|
+
|
|
296
|
+
## Bots Panel (Ctrl+D)
|
|
297
|
+
|
|
298
|
+
Shows all your strategies with status:
|
|
299
|
+
- Running strategies show a spinner
|
|
300
|
+
- Stopped strategies show a dash
|
|
301
|
+
- Error strategies show an x
|
|
302
|
+
|
|
303
|
+
Navigate with arrow keys, Enter to expand details.
|
|
304
|
+
|
|
305
|
+
## Actions
|
|
306
|
+
|
|
307
|
+
When a strategy is expanded:
|
|
308
|
+
- **r** — restart a stopped strategy (redeploys with same settings)
|
|
309
|
+
- **p** — pause a running strategy
|
|
310
|
+
- **k** — kill a running strategy
|
|
311
|
+
|
|
312
|
+
## Metrics
|
|
313
|
+
|
|
314
|
+
When metrics are available for running strategies:
|
|
315
|
+
|
|
316
|
+
| Metric | Meaning |
|
|
317
|
+
|--------|---------|
|
|
318
|
+
| Total P&L | Net profit/loss |
|
|
319
|
+
| Realized P&L | Closed position profits |
|
|
320
|
+
| Unrealized P&L | Open position mark-to-market |
|
|
321
|
+
| Win Rate | Percentage of profitable trades |
|
|
322
|
+
| Max Drawdown | Largest peak-to-trough decline |
|
|
323
|
+
| Sharpe Ratio | Risk-adjusted return (>1 is good, >2 is great) |
|
|
324
|
+
| Sortino Ratio | Like Sharpe but only penalizes downside |
|
|
325
|
+
| Profit Factor | Gross profit / gross loss (>1.5 is good) |
|
|
326
|
+
| Expectancy | Average profit per trade |
|
|
327
|
+
|
|
328
|
+
## AI Tools
|
|
329
|
+
|
|
330
|
+
In portfolio mode, the AI has these tools:
|
|
331
|
+
- **list_strategies** — see all strategies
|
|
332
|
+
- **get_strategy** — full detail with code
|
|
333
|
+
- **list_deployments** — deployment history
|
|
334
|
+
- **get_metrics** — live P&L, positions, orders
|
|
335
|
+
- **get_logs** — recent bot output
|
|
336
|
+
- **deploy_strategy** — deploy to paper or live
|
|
337
|
+
- **stop_strategy** — stop a deployment
|
|
338
|
+
`,
|
|
339
|
+
|
|
340
|
+
settings: `# Settings & Configuration
|
|
341
|
+
|
|
342
|
+
Open with **/settings**. Navigate with arrow keys, left/right to change.
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Intelligence
|
|
347
|
+
|
|
348
|
+
Controls which AI model powers your chat:
|
|
349
|
+
|
|
350
|
+
| Level | Model | Budget multiplier |
|
|
351
|
+
|-------|-------|-------------------|
|
|
352
|
+
| **Fast** | Hunter Alpha | 0.25x (cheapest) |
|
|
353
|
+
| **Standard** | Claude Haiku 4.5 | 1x |
|
|
354
|
+
| **Pro** | Claude Sonnet 4.6 | 2x (Pro plan+) |
|
|
355
|
+
| **Ultra** | Claude Opus 4.6 | 4x (Ultra plan only) |
|
|
356
|
+
|
|
357
|
+
Higher intelligence = smarter responses but drains your token
|
|
358
|
+
budget faster. Fast is great for simple queries.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## Response Style
|
|
363
|
+
|
|
364
|
+
- **Short** — 1-2 sentences max. Terse, no elaboration.
|
|
365
|
+
- **Normal** — balanced (default)
|
|
366
|
+
- **Verbose** — detailed explanations with reasoning
|
|
367
|
+
|
|
368
|
+
Does NOT affect code generation in strategy mode.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Hooks
|
|
373
|
+
|
|
374
|
+
Open with **/hooks**. Custom bash commands that run at strategy
|
|
375
|
+
lifecycle points. Each hook shows output in chat.
|
|
376
|
+
|
|
377
|
+
| Event | When it runs |
|
|
378
|
+
|-------|-------------|
|
|
379
|
+
| before_generate | Before AI writes strategy code |
|
|
380
|
+
| after_generate | After code is proposed |
|
|
381
|
+
| before_validate | Before validation check |
|
|
382
|
+
| before_backtest | Before running backtest |
|
|
383
|
+
| before_deploy | Before deploying to cloud |
|
|
384
|
+
| after_deploy | After deploy succeeds |
|
|
385
|
+
|
|
386
|
+
**Adding a hook:** press \`a\`, select event, type command, enter.
|
|
387
|
+
**Example:** \`before_deploy\` -> \`ruff check strategy.py\`
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Encrypted API Keys
|
|
392
|
+
|
|
393
|
+
Store keys for SDK integrations (Alpaca, Unusual Whales, etc.):
|
|
394
|
+
|
|
395
|
+
\`/env add ALPACA_KEY sk-your-key-here\`
|
|
396
|
+
\`/env list\` — see stored keys
|
|
397
|
+
\`/env remove ALPACA_KEY\` — delete a key
|
|
398
|
+
|
|
399
|
+
Keys are encrypted with **AES-256-GCM** using a key derived from
|
|
400
|
+
your Horizon API key. Stored in ~/.horizon/config.json.
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## Safety Controls
|
|
405
|
+
|
|
406
|
+
**Pay As You Go** — off by default. When on, allows extra charges
|
|
407
|
+
if your token budget runs out. When off, hard stop.
|
|
408
|
+
|
|
409
|
+
**Live Trading** — off by default. Must be enabled to deploy live
|
|
410
|
+
strategies. Paper mode only until you turn this on.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Themes
|
|
415
|
+
|
|
416
|
+
Four themes: **Dark** (default), **Midnight**, **Nord**, **Solarized**.
|
|
417
|
+
Restart to fully apply.
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Other Settings
|
|
422
|
+
|
|
423
|
+
- **Auto Focus** — focus input after sending a message
|
|
424
|
+
- **Smart Compact** — auto-compact context when it gets full
|
|
425
|
+
- **Compact Warning** — threshold % to warn about context usage
|
|
426
|
+
- **Show Tool Calls** — show/hide tool call indicators in chat
|
|
427
|
+
- **Sound** — terminal bell on generation complete
|
|
428
|
+
`,
|
|
429
|
+
|
|
430
|
+
commands: `# Commands
|
|
431
|
+
|
|
432
|
+
Type \`/\` to see autocomplete suggestions as you type.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## Chat
|
|
437
|
+
|
|
438
|
+
| Command | Action |
|
|
439
|
+
|---------|--------|
|
|
440
|
+
| /clear | Clear current chat messages |
|
|
441
|
+
| /compact | Force context compaction |
|
|
442
|
+
| /context | Show context window usage |
|
|
443
|
+
|
|
444
|
+
## Auth
|
|
445
|
+
|
|
446
|
+
| Command | Action |
|
|
447
|
+
|---------|--------|
|
|
448
|
+
| /login | Browser auth (Google) |
|
|
449
|
+
| /login email pass | Email/password login |
|
|
450
|
+
| /logout | Sign out |
|
|
451
|
+
| /whoami | Show current user |
|
|
452
|
+
|
|
453
|
+
## Panels
|
|
454
|
+
|
|
455
|
+
| Command | Action |
|
|
456
|
+
|---------|--------|
|
|
457
|
+
| /settings | Open settings panel |
|
|
458
|
+
| /hooks | Manage lifecycle hooks |
|
|
459
|
+
| /tutorial | This guide |
|
|
460
|
+
| /code | Toggle code panel |
|
|
461
|
+
| /home | Back to splash screen |
|
|
462
|
+
|
|
463
|
+
## Mode
|
|
464
|
+
|
|
465
|
+
| Command | Action |
|
|
466
|
+
|---------|--------|
|
|
467
|
+
| /mode | Cycle research/strategy/portfolio |
|
|
468
|
+
| /mode research | Switch to research |
|
|
469
|
+
| /mode strategy | Switch to strategy |
|
|
470
|
+
| /usage | Toggle metrics display |
|
|
471
|
+
| /privacy | Toggle privacy mode |
|
|
472
|
+
|
|
473
|
+
## Strategy
|
|
474
|
+
|
|
475
|
+
| Command | Action |
|
|
476
|
+
|---------|--------|
|
|
477
|
+
| /strategies | List saved strategies on disk |
|
|
478
|
+
| /load name | Load a saved strategy |
|
|
479
|
+
|
|
480
|
+
## Environment
|
|
481
|
+
|
|
482
|
+
| Command | Action |
|
|
483
|
+
|---------|--------|
|
|
484
|
+
| /env list | Show stored encrypted keys |
|
|
485
|
+
| /env add NAME VALUE | Store an encrypted API key |
|
|
486
|
+
| /env remove NAME | Delete a stored key |
|
|
487
|
+
| /tutorial | This guide |
|
|
488
|
+
|
|
489
|
+
## Context
|
|
490
|
+
|
|
491
|
+
| Command | Action |
|
|
492
|
+
|---------|--------|
|
|
493
|
+
| /compact | Force context compaction |
|
|
494
|
+
| /context | Show context window usage |
|
|
495
|
+
|
|
496
|
+
## System
|
|
497
|
+
|
|
498
|
+
| Command | Action |
|
|
499
|
+
|---------|--------|
|
|
500
|
+
| /help | List all commands |
|
|
501
|
+
| /quit | Exit Horizon |
|
|
502
|
+
|
|
503
|
+
## Keyboard Shortcuts
|
|
504
|
+
|
|
505
|
+
| Key | Action |
|
|
506
|
+
|-----|--------|
|
|
507
|
+
| Ctrl+R | Cycle mode |
|
|
508
|
+
| Ctrl+E | Toggle sessions panel |
|
|
509
|
+
| Ctrl+D | Toggle bots panel |
|
|
510
|
+
| Ctrl+G | Toggle code panel |
|
|
511
|
+
| Ctrl+T | Toggle metrics display |
|
|
512
|
+
| Ctrl+P | Toggle privacy mode |
|
|
513
|
+
| Ctrl+1/2/3 | Code panel tabs |
|
|
514
|
+
| Esc | Stop generation / close panel |
|
|
515
|
+
| PageUp/Down | Scroll chat |
|
|
516
|
+
`,
|
|
517
|
+
|
|
518
|
+
tips: `# Tips
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
## Research
|
|
523
|
+
|
|
524
|
+
- **Be specific** — *"order book for btc-100k"* beats *"show me bitcoin"*
|
|
525
|
+
- **Chain requests** — *"analyze the first one"* reuses the slug
|
|
526
|
+
- **EV before betting** — calculates Kelly sizing from your edge
|
|
527
|
+
- **Cross-platform** — *"compare bitcoin Polymarket vs Kalshi"* for arb
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## Strategy
|
|
532
|
+
|
|
533
|
+
- **Let it research first** — the AI checks real spreads before coding
|
|
534
|
+
- **Paper mode default** — always starts safe. Enable Live in /settings
|
|
535
|
+
- **Backtest before deploy** — real \`hz.backtest()\` metrics
|
|
536
|
+
- **Small edits** — the AI uses find/replace for tweaks, full rewrite for rewrites
|
|
537
|
+
- **Ctrl+G** — code panel shows validation status (green = valid)
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## Performance
|
|
542
|
+
|
|
543
|
+
- **Ctrl+T** — toggle metrics bar (context %, budget, tokens)
|
|
544
|
+
- **Smart compact** — enabled by default, prompts before compacting
|
|
545
|
+
- **/compact** — force compaction when context is high
|
|
546
|
+
- **Queue messages** — send while generating, they process in order
|
|
547
|
+
- **Esc** — interrupt generation. Queue pauses with /resume
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## Security
|
|
552
|
+
|
|
553
|
+
- **Sandboxed execution** — strategy code runs in temp dirs, no secrets
|
|
554
|
+
- **Server-side enforcement** — budget, rate limits, model access checked server-side
|
|
555
|
+
- **Encrypted env vars** — \`/env add\` stores keys with AES-256-GCM
|
|
556
|
+
- **Paper mode guard** — /settings → Live Trading must be ON for live deploys
|
|
557
|
+
- **Config permissions** — ~/.horizon/config.json is 0600 (owner only)
|
|
558
|
+
`,
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
export class TutorialPanel {
|
|
562
|
+
readonly container: BoxRenderable;
|
|
563
|
+
private tabBar: BoxRenderable;
|
|
564
|
+
private tabTexts: Map<TutorialTab, TextRenderable> = new Map();
|
|
565
|
+
private contentScroll: ScrollBoxRenderable;
|
|
566
|
+
private contentMd: MarkdownRenderable;
|
|
567
|
+
private _visible = false;
|
|
568
|
+
private _activeTab: TutorialTab = "start";
|
|
569
|
+
|
|
570
|
+
constructor(private renderer: CliRenderer) {
|
|
571
|
+
this.container = new BoxRenderable(renderer, {
|
|
572
|
+
id: "tutorial-panel",
|
|
573
|
+
width: "50%",
|
|
574
|
+
height: "100%",
|
|
575
|
+
flexDirection: "column",
|
|
576
|
+
borderColor: COLORS.borderDim,
|
|
577
|
+
});
|
|
578
|
+
this.container.visible = false;
|
|
579
|
+
|
|
580
|
+
// Tab bar
|
|
581
|
+
this.tabBar = new BoxRenderable(renderer, {
|
|
582
|
+
id: "tutorial-tabs",
|
|
583
|
+
height: 1,
|
|
584
|
+
width: "100%",
|
|
585
|
+
flexDirection: "row",
|
|
586
|
+
alignItems: "center",
|
|
587
|
+
paddingLeft: 1,
|
|
588
|
+
paddingRight: 1,
|
|
589
|
+
backgroundColor: COLORS.bgDarker,
|
|
590
|
+
flexShrink: 0,
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
for (const tab of TAB_LIST) {
|
|
594
|
+
const text = new TextRenderable(renderer, {
|
|
595
|
+
id: `tutorial-tab-${tab.id}`,
|
|
596
|
+
content: ` ${tab.label} `,
|
|
597
|
+
fg: COLORS.textMuted,
|
|
598
|
+
});
|
|
599
|
+
this.tabTexts.set(tab.id, text);
|
|
600
|
+
this.tabBar.add(text);
|
|
601
|
+
}
|
|
602
|
+
this.container.add(this.tabBar);
|
|
603
|
+
|
|
604
|
+
// Content area
|
|
605
|
+
this.contentScroll = new ScrollBoxRenderable(renderer, {
|
|
606
|
+
id: "tutorial-scroll",
|
|
607
|
+
flexGrow: 1,
|
|
608
|
+
paddingLeft: 2,
|
|
609
|
+
paddingRight: 2,
|
|
610
|
+
paddingTop: 1,
|
|
611
|
+
stickyScroll: false,
|
|
612
|
+
});
|
|
613
|
+
this.contentMd = new MarkdownRenderable(renderer, {
|
|
614
|
+
id: "tutorial-md",
|
|
615
|
+
content: CONTENT.start,
|
|
616
|
+
syntaxStyle,
|
|
617
|
+
});
|
|
618
|
+
this.contentScroll.add(this.contentMd);
|
|
619
|
+
this.container.add(this.contentScroll);
|
|
620
|
+
|
|
621
|
+
// Footer
|
|
622
|
+
this.container.add(new TextRenderable(renderer, {
|
|
623
|
+
id: "tutorial-footer",
|
|
624
|
+
content: " < > switch tab | /tutorial to close",
|
|
625
|
+
fg: COLORS.borderDim,
|
|
626
|
+
}));
|
|
627
|
+
|
|
628
|
+
this.updateTabBar();
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
get visible(): boolean { return this._visible; }
|
|
632
|
+
|
|
633
|
+
show(): void {
|
|
634
|
+
this._visible = true;
|
|
635
|
+
this.container.visible = true;
|
|
636
|
+
this.renderer.requestRender();
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
hide(): void {
|
|
640
|
+
this._visible = false;
|
|
641
|
+
this.container.visible = false;
|
|
642
|
+
this.renderer.requestRender();
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
toggle(): void {
|
|
646
|
+
if (this._visible) this.hide();
|
|
647
|
+
else this.show();
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
setTab(tab: TutorialTab): void {
|
|
651
|
+
this._activeTab = tab;
|
|
652
|
+
this.contentMd.content = CONTENT[tab];
|
|
653
|
+
this.updateTabBar();
|
|
654
|
+
this.renderer.requestRender();
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
nextTab(): void {
|
|
658
|
+
const idx = TAB_LIST.findIndex((t) => t.id === this._activeTab);
|
|
659
|
+
this.setTab(TAB_LIST[(idx + 1) % TAB_LIST.length]!.id);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
prevTab(): void {
|
|
663
|
+
const idx = TAB_LIST.findIndex((t) => t.id === this._activeTab);
|
|
664
|
+
this.setTab(TAB_LIST[(idx - 1 + TAB_LIST.length) % TAB_LIST.length]!.id);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
private updateTabBar(): void {
|
|
668
|
+
for (const [id, text] of this.tabTexts) {
|
|
669
|
+
if (id === this._activeTab) {
|
|
670
|
+
text.fg = "#212121";
|
|
671
|
+
text.bg = COLORS.secondary;
|
|
672
|
+
text.content = ` ${TAB_LIST.find((t) => t.id === id)!.label} `;
|
|
673
|
+
} else {
|
|
674
|
+
text.fg = COLORS.textMuted;
|
|
675
|
+
text.bg = undefined;
|
|
676
|
+
text.content = ` ${TAB_LIST.find((t) => t.id === id)!.label} `;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { TextRenderable, type CliRenderer } from "@opentui/core";
|
|
2
|
+
import { COLORS } from "../../theme/colors.ts";
|
|
3
|
+
import { ICONS } from "../../theme/icons.ts";
|
|
4
|
+
|
|
5
|
+
export class ProgressBar {
|
|
6
|
+
private text: TextRenderable;
|
|
7
|
+
|
|
8
|
+
constructor(
|
|
9
|
+
renderer: CliRenderer,
|
|
10
|
+
id: string,
|
|
11
|
+
private width: number = 20,
|
|
12
|
+
) {
|
|
13
|
+
this.text = new TextRenderable(renderer, {
|
|
14
|
+
id,
|
|
15
|
+
content: "",
|
|
16
|
+
fg: COLORS.textMuted,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get renderable(): TextRenderable {
|
|
21
|
+
return this.text;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
setValue(pct: number, label?: string): void {
|
|
25
|
+
const clamped = Math.max(0, Math.min(100, pct));
|
|
26
|
+
const filled = Math.round((clamped / 100) * this.width);
|
|
27
|
+
const empty = this.width - filled;
|
|
28
|
+
|
|
29
|
+
const bar = ICONS.barFull.repeat(filled) + ICONS.barEmpty.repeat(empty);
|
|
30
|
+
const suffix = label ?? `${clamped.toFixed(0)}%`;
|
|
31
|
+
|
|
32
|
+
this.text.content = `${bar} ${suffix}`;
|
|
33
|
+
|
|
34
|
+
if (clamped <= 60) this.text.fg = COLORS.success;
|
|
35
|
+
else if (clamped <= 80) this.text.fg = COLORS.warning;
|
|
36
|
+
else this.text.fg = COLORS.error;
|
|
37
|
+
}
|
|
38
|
+
}
|