65 lines
2.8 KiB
Markdown
65 lines
2.8 KiB
Markdown
# stonks
|
|
|
|
Daily financial news + market data analysis. Fetches crypto/equity/futures prices (yfinance-equivalent + Finnhub) and market news (RSS), asks Claude for an investment-advice briefing, and posts it to Discord — on a systemd user timer.
|
|
|
|
See [PLAN.md](PLAN.md) for the full design, cost analysis, and rationale.
|
|
|
|
## Build
|
|
|
|
```sh
|
|
make build
|
|
```
|
|
|
|
## Configure
|
|
|
|
```sh
|
|
mkdir -p ~/.config/stonks
|
|
cp config/config.yaml ~/.config/stonks/config.yaml
|
|
cp config/secrets.env.example ~/.config/stonks/secrets.env
|
|
chmod 600 ~/.config/stonks/secrets.env
|
|
$EDITOR ~/.config/stonks/secrets.env # fill in FINNHUB_API_KEY, DISCORD_WEBHOOK_URL, (ANTHROPIC_API_KEY if using api mode)
|
|
```
|
|
|
|
If `analyzer.mode: subscription` (the default), install Claude Code and authenticate once:
|
|
|
|
```sh
|
|
claude login
|
|
```
|
|
|
|
### Multi-agent mode (optional)
|
|
|
|
`analyzer.advisors` in `config.yaml` lists additional CLI-based AI analysts (Gemini, Codex) that get the same fetched data and produce an independent take; their output is appended to Claude's prompt as extra context (Claude still writes the one final report — see PLAN.md § "Claude integration"). Each needs to be installed and logged in separately:
|
|
|
|
```sh
|
|
gemini # first run walks through auth
|
|
codex login
|
|
```
|
|
|
|
A failing or unauthenticated advisor is logged as a warning and simply excluded — it never fails the run. Remove an entry (or the whole `advisors:` list) to disable multi-agent mode.
|
|
|
|
### Archiving runs
|
|
|
|
Every run saves its fetched data, full prompt (including any advisor section), raw and parsed analysis to `archive.dir` (default `~/.local/state/stonks/runs`), one timestamped subdirectory per run: `fetched.json`, `prompt.txt`, `analysis_raw.md`, `report.md`, `recommendations.json`. This is always on — besides being useful for debugging prompt or parsing issues, the next run reads back `report.md` from the most recent subdirectory so it can avoid repeating unchanged commentary from ~5 hours ago. These accumulate over time with no automatic cleanup.
|
|
|
|
## Install as a user-scope systemd service
|
|
|
|
```sh
|
|
mkdir -p ~/.config/systemd/user
|
|
make install # builds and installs to ~/.local/bin/stonks
|
|
cp systemd/stonks.service systemd/stonks.timer ~/.config/systemd/user/
|
|
systemctl --user daemon-reload
|
|
systemctl --user enable --now stonks.timer
|
|
loginctl enable-linger "$USER" # keep the timer firing while logged out
|
|
```
|
|
|
|
Run it once manually to verify before waiting for the timer:
|
|
|
|
```sh
|
|
systemctl --user start stonks.service
|
|
journalctl --user -u stonks.service -f
|
|
```
|
|
|
|
## Adding a new fetcher / output
|
|
|
|
Implement the `fetch.Fetcher` / `output.Output` interface in a new file under `internal/fetch` / `internal/output`, self-register it in an `init()` (see `internal/fetch/rss.go` for an example), add the name to `config.yaml`, and rebuild. See PLAN.md § "Modularity in Go" for why this is compile-time rather than a runtime plugin system.
|