Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
6b2cb43
(feat) apply improvements requested by ralph
cardosofede Aug 18, 2026
c06d7a6
(feat) improved menu
cardosofede Aug 19, 2026
26cdcf4
(feat) improved gateway token fetch
cardosofede Aug 19, 2026
f7223aa
(perf) build agent PnL series in one merge pass instead of per-stamp …
cardosofede Aug 19, 2026
7be5aff
(fix) stop browser password managers capturing the gateway wallet pri…
cardosofede Aug 19, 2026
28aefa6
(fix) DEX pool charts freeze after backfill: candle keys omitted pool…
cardosofede Aug 19, 2026
6dec57c
(fix) subscribe DexPool to executors WS and let fresh by-pool LP rows…
cardosofede Aug 19, 2026
2497219
(perf) stop rebuilding executor overlays on every candle tick
cardosofede Aug 19, 2026
b1a5440
(fix) make SDS ticker/price fetchers strict so failures keep the last…
cardosofede Aug 19, 2026
94ce7ed
(fix) route agent durable writes through fsutil atomic helpers (CORR-…
cardosofede Aug 19, 2026
4907856
(perf) bound archived-bot cache with LRU and single-flight fetch (PER…
cardosofede Aug 19, 2026
5e296c3
(refactor) prune 15 dead public accessors from condor/preferences.py …
cardosofede Aug 19, 2026
0f1f59c
(refactor) reuse resolve_custom_endpoint in chat-session path (ARCH-199)
cardosofede Aug 19, 2026
251c40f
(fix) gate body-supplied chat_id behind caller ownership (SEC-198)
cardosofede Aug 19, 2026
eb9a884
(fix) scope backtest fetch/delete to the path server (SEC-197)
cardosofede Aug 19, 2026
07f35b2
(refactor) remove dead Telegram Login Widget auth path (READ-201)
cardosofede Aug 19, 2026
48d2ea5
(perf) bound _CLOSED_PERF_CACHE with an LRU cap (PERF-186)
cardosofede Aug 19, 2026
8da9170
(fix) TradeBottomPane stop/clear invalidate the pane's own query keys
cardosofede Aug 19, 2026
b4410bb
(fix) keep throttle errors out of the pasted-pool cache so DexPool ca…
cardosofede Aug 19, 2026
93ec1be
(fix) re-apply price precision once lazy chart series exists (CORR-184)
cardosofede Aug 19, 2026
09709a3
(fix) fetch DEX favorites beyond 30 in batches instead of truncating
cardosofede Aug 19, 2026
237de45
(fix) clipboard copy fallback for non-HTTPS origins
cardosofede Aug 19, 2026
a566c41
(refactor) dedupe dex num/usd/pct formatters into shared module
cardosofede Aug 19, 2026
0f12fb5
(refactor) dedup significant-digits price formatter into lib formatPr…
cardosofede Aug 19, 2026
16f1970
(refactor) TradeBottomPane reuses usePairBalances instead of inline p…
cardosofede Aug 19, 2026
b05f342
(fix) dex-pools query key matches request params, no spurious refetch…
cardosofede Aug 19, 2026
ac81238
(perf) un-star a favorite without refetching the whole list
cardosofede Aug 19, 2026
f45898d
(fix) sort missing pool figures last in both directions
cardosofede Aug 19, 2026
fe95439
(refactor) Dex.tsx reads the gateway-tab chain rule from GATEWAY_TAB_…
cardosofede Aug 19, 2026
15c8881
(refactor) remove dead onRequestCandleRange prop from TradeChart
cardosofede Aug 19, 2026
3164244
(refactor) extract shared ExecutorSuccessModal and ErrorToast (ARCH-195)
cardosofede Aug 19, 2026
23611bf
(fix) serialize concurrent session creation per key (CORR-187)
cardosofede Aug 19, 2026
17b6a12
(perf) cache instance-history cursor walks with TTL + in-flight coale…
cardosofede Aug 19, 2026
5ad0e46
(refactor) consolidate frontmatter round-trip and slugify into condor…
cardosofede Aug 19, 2026
aa27ec4
(fix) scope reports API to the report's owner (SEC-196)
cardosofede Aug 19, 2026
edd8aa5
(feat) update telemetry and general improvements
cardosofede Aug 19, 2026
df22d27
(feat) add llm client
cardosofede Aug 19, 2026
7160780
(fix) repoint runtime test client patches at the defining modules (AR…
cardosofede Aug 19, 2026
5eeea2c
(refactor) remove dead refactor leftovers: is_hosted, should_flush, _…
cardosofede Aug 19, 2026
0a19cad
(fix) redact gateway RPC credentials from non-owner network config re…
cardosofede Aug 19, 2026
940bb89
(refactor) decouple pool_data from the Telegram handler cache
cardosofede Aug 19, 2026
3244c24
(refactor) move agent runtime foundations from handlers/ into condor/…
cardosofede Aug 19, 2026
93360a1
(refactor) extract session-ownership PnL attribution engine into cond…
cardosofede Aug 19, 2026
196c0fb
(refactor) split WebSocketManager god class: extract candle and Hummi…
cardosofede Aug 19, 2026
1cbc5dc
(feat) remove agents
cardosofede Aug 19, 2026
fec6958
(feat) apply improvements claude review
cardosofede Aug 19, 2026
3726ed8
(feat) add Gateway token registration button to pool banner: retry fa…
cardosofede Aug 19, 2026
2340c08
(fix) label LP chart lines as Upper/Lower/Upper limit instead of grid…
cardosofede Aug 20, 2026
84a2531
(feat) last comments from ralph
cardosofede Aug 20, 2026
bdf07d9
(feat) fix portfolio
cardosofede Aug 20, 2026
43eab08
(feat) task notifications reach the dashboard: per-user store, WS pus…
cardosofede Aug 20, 2026
be6a0cf
(feat) notification bell in the dashboard top bar
cardosofede Aug 20, 2026
446e4b7
(feat) condor runs without telegram: explicit CONDOR_MODE, local boot…
cardosofede Aug 20, 2026
ac0544b
(feat) local mode setup question, dashboard auto-login and docs
cardosofede Aug 20, 2026
1bd487b
(fix) local mode logs in as ADMIN_USER_ID, and a broken mode fails at…
cardosofede Aug 21, 2026
ed2eeb7
(test) add the tests for default-server sync, DEX upstream status and…
cardosofede Aug 21, 2026
3bb324f
(feat) count every install and ask for telemetry consent in the dashb…
cardosofede Aug 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,38 @@ check-stopped:
exit 1; \
fi

# `remain-on-exit` keeps the pane alive after the process dies, so a startup
# failure can be read back with capture-pane instead of scrolling away with the
# session. Config errors (a bad ADMIN_USER_ID, a mode with no token, a local user
# config.yml has never heard of) exit in the first second and used to leave
# nothing behind but "run make run-fg to see the error".
#
# It is turned back off the moment the boot is confirmed: a crash three hours
# later must still take the session with it, or `make status` and `check-stopped`
# would report a dead Condor as running.
run: check-stopped build-frontend
@tmux new-session -d -s $(SESSION) -c "$(CURDIR)" 'uv run python main.py'
@sleep 2
@if tmux has-session -t $(SESSION) 2>/dev/null; then \
echo "Condor started in tmux session '$(SESSION)'."; \
echo " make logs - attach (detach: Ctrl+B then D)"; \
echo " make stop - stop Condor"; \
else \
@tmux set-option -t $(SESSION) remain-on-exit on >/dev/null 2>&1 \
|| tmux set-window-option -t $(SESSION) remain-on-exit on >/dev/null 2>&1 || true
@sleep 3
@if ! tmux has-session -t $(SESSION) 2>/dev/null; then \
echo "Condor exited on startup. Run 'make run-fg' to see the error."; \
exit 1; \
fi
@if [ "$$(tmux list-panes -t $(SESSION) -F '#{pane_dead}' 2>/dev/null | head -1)" = "1" ]; then \
echo "Condor exited on startup:"; \
echo ""; \
tmux capture-pane -p -t $(SESSION) 2>/dev/null | grep -v '^[[:space:]]*$$' | tail -20 | sed 's/^/ /'; \
echo ""; \
echo " make run-fg - run in the foreground for the full output"; \
tmux kill-session -t $(SESSION) >/dev/null 2>&1 || true; \
exit 1; \
fi
@tmux set-option -t $(SESSION) remain-on-exit off >/dev/null 2>&1 \
|| tmux set-window-option -t $(SESSION) remain-on-exit off >/dev/null 2>&1 || true
@echo "Condor started in tmux session '$(SESSION)'."
@echo " make logs - attach (detach: Ctrl+B then D)"
@echo " make stop - stop Condor"

run-fg: build-frontend
uv run python main.py
Expand Down
84 changes: 51 additions & 33 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
# Privacy

Condor is self-hosted. It runs on your machine, holds your exchange API keys,
and places your orders. So the default for anything that could leave that
machine is **off**, and this document is the complete statement of what the one
optional exception does.

**Short version:** a fresh install sends nothing. It has no telemetry consent
recorded, which resolves to level `off`, at which the emitter returns before it
has looked at its arguments — no buffer, no file, no directory. Nothing changes
until an admin taps "yes" on a prompt. Even then, this repository has no
collector address compiled into it: with `CONDOR_TELEMETRY_URL` unset, the send
path is inert and events can only ever reach a capped local file.
and places your orders. So what leaves that machine by default is the absolute
minimum — an anonymous "this install exists" — and everything beyond that is
opt-in. This document is the complete statement of both.

**Short version:** a fresh install counts itself and nothing more. With no
consent recorded it runs at level `ping`: a random install id, the version, and
a periodic heartbeat — nothing about you, your users, or your trading. None of
the usage events are sent until an admin taps "yes" on a prompt. Batches go to
the project's collector at `https://telemetry.hummingbot.org/v1/events`, which
is fixed in the source and cannot be pointed elsewhere. The one full kill
switch is `CONDOR_TELEMETRY=off` in the environment.

The whole mechanism is about 900 lines in [`condor/telemetry/`](condor/telemetry/).
It is meant to be read, not trusted.

---

## What is collected, if you opt in
## What is collected

There are three levels. You choose one; you can change it later.
There are three levels. The consent prompt chooses between `ping` and `usage`;
`off` exists only as an environment override. You can change the answer later.

| Level | What it sends |
|---|---|
| `off` | Nothing, ever. The emitter is a no-op. **This is the default.** |
| `ping` | Only that this install exists: `install`, `heartbeat`, `version_change`, `shutdown`. |
| `usage` | The above plus the feature, reliability and agent events below. |
| `ping` | Only that this install exists: `install`, `heartbeat`, `version_change`, `shutdown`. **This is the default, and the floor** — the prompt has no "off" option. |
| `usage` | The above plus the feature, reliability and agent events below. Opt-in only. |
| `off` | Nothing, ever. The emitter is a no-op. Reachable only via `CONDOR_TELEMETRY=off` in the environment. |

Every batch carries one context block describing the *deployment*, not you:

Expand All @@ -35,6 +37,7 @@ Every batch carries one context block describing the *deployment*, not you:
| `app.version`, `app.branch` | `54ad4dc`, `main` | Which commit is actually running, so we know what to support. |
| `app.python`, `app.os`, `app.arch`, `app.in_docker` | `3.12`, `linux`, `arm64`, `true` | What to test against. |
| `config.*` | `has_gateway: true`, `user_count: 3`, `server_count: 2`, `llm_providers: ["openai"]` | Counts and capability flags. Numbers and fixed provider *names* — never a server name, never a URL, never a key. |
| `config.mode` | `telegram` or `local` | Whether the install runs Telegram at all, or only the dashboard. One of two fixed names. |
| `dropped` | `0` | How many events the rate limiter discarded. An honest count, so a quiet incident is visibly quiet. |

And the events themselves:
Expand Down Expand Up @@ -94,47 +97,62 @@ per-install, the same person on two installs produces two unrelated hashes.

## Where it goes

Nowhere, unless you configure a destination.
At the default `ping` level, only the four adoption events and the envelope
above. Everything else needs an explicit opt-in.

Batches are POSTed to `https://telemetry.hummingbot.org/v1/events`.
That address is compiled into
[`condor/telemetry/outbox.py`](condor/telemetry/outbox.py) as `COLLECTOR_URL`
and is not configurable — there is no environment variable or config key that
redirects it, so the only way to change where your data goes is to edit that
line in your own checkout. The collector itself is open source
(`condor-telemetry-server`).

No collector URL is compiled into this repository. Events are buffered in memory
and, when a batch cannot be delivered, appended to
Events are buffered in memory and, when a batch cannot be delivered, appended to
`condor/.runtime/telemetry/outbox.jsonl`, which is capped at 5,000 events and 7
days — oldest dropped. With `CONDOR_TELEMETRY_URL` unset, that is the entire
life cycle: a local file, capped, that you can delete.
days — oldest dropped. At level `off` no event is ever created, so nothing is
buffered, nothing is written, and nothing is sent.

You can read exactly what would be sent:

```bash
cat condor/.runtime/telemetry/outbox.jsonl | jq .
```

## How to turn it off — or check it is off
## How to change it — or turn it off entirely

It is already off unless you turned it on. To be certain:
Install counting (`ping`) is the floor: it is not an option on the consent
prompt and cannot be disabled from the dashboard, because the project needs an
honest count of installs to know what to support. To check what your install is
doing:

```bash
# The authoritative answer. Prints "off" on a default install.
# The authoritative answer. Prints "ping" on a default install,
# "off" only when CONDOR_TELEMETRY=off is set.
uv run python -c "from condor.telemetry import consent; print(consent.level())"
```

Three ways to control it, in order of precedence:

1. **Environment** — `CONDOR_TELEMETRY=off` in your `.env`. This overrides
everything, in both directions, and is the right answer for a headless or
containerized install. `CONDOR_TELEMETRY_URL` is what enables sending at all;
leave it unset and nothing can be transmitted.
2. **The dashboard API** — `PUT /api/v1/settings/telemetry?level=off` (admin
only). `GET` the same path to see the current state.
1. **Environment** — `CONDOR_TELEMETRY=off` in your `.env`. The one full kill
switch: it overrides everything, suppresses the prompt, and is the right
answer for an install that must send nothing at all.
2. **The dashboard** — Settings → Privacy, which every seat can read and only
the admin can change (`GET`/`PUT /api/v1/settings/telemetry?level=ping|usage`;
`off` is rejected there). This is also where an install that runs without
Telegram is asked in the first place, since it has no bot to be asked
through.
3. **`config.yml`** — edit the `telemetry` section directly:

```yaml
telemetry:
consent: denied
level: off
consent: granted
level: ping
```

Turning it off is a **withdrawal, not a pause**: the in-memory buffer and the
outbox file are deleted, so nothing already recorded can be sent afterwards.
Downgrading from `usage` to `ping` is a **withdrawal, not a pause**: the
in-memory buffer and the outbox file are deleted, so nothing already recorded
can be sent afterwards.

## Changes to this document

Expand Down
59 changes: 51 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ A Telegram bot for monitoring and trading with Hummingbot via the **Hummingbot A
>
> Full walkthrough: [Securing Condor and Hummingbot API with Tailscale](https://hummingbot.org/blog/posts/securing-condor-and-hummingbot-api-with-tailscale/) · [Hummingbot API Tailscale guide](https://hummingbot.org/hummingbot-api/tailscale/)

> **Privacy:** Condor collects nothing by default. It ships with usage telemetry
> **off** and no collector address, and it stays that way unless an admin
> explicitly opts in from the one prompt it sends on first boot. What that
> option would and would not collect — and how to verify it is off — is spelled
> out in [PRIVACY.md](PRIVACY.md).
> **Privacy:** Condor counts installs anonymously — a random id, the version,
> and a heartbeat; nothing about you or your trading. Everything beyond that is
> **opt-in** from the one prompt it sends on first boot, and
> `CONDOR_TELEMETRY=off` silences telemetry entirely. What each level does and
> does not collect, where it goes, and how to verify it, is spelled out in
> [PRIVACY.md](PRIVACY.md).

## Features

Expand Down Expand Up @@ -54,7 +55,7 @@ Open Terminal, go to an **empty folder** where you are happy to create files (fo
curl -fsSL https://raw.githubusercontent.com/hummingbot/deploy/main/setup.sh | bash
```

The installer walks you through setup—for example your **Telegram** bot token and your **Telegram user id**—and can also install **Hummingbot API** on the **same machine** if you choose that when it asks.
The installer first asks **how you will use Condor**: **Telegram** (a bot you control from your phone — recommended) or **Local** (no Telegram at all, see [Local mode](#local-mode-no-telegram) below). If you choose Telegram it asks for your bot token and your Telegram user id. Either way it can also install **Hummingbot API** on the **same machine** if you choose that when it asks.

When installing Hummingbot API, answer **`y`** when asked to enable Tailscale and paste your auth key. When it finishes, continue to **After installation** below.

Expand Down Expand Up @@ -96,6 +97,41 @@ The following applies after **Install Condor**. If you used **Install only Hummi
- If Condor and the API are on **different machines**, install [Tailscale](https://tailscale.com/download) on the Condor host and add the API in **`/servers`** with host **`hummingbot-api`** (not a public IP). See [Secure Connection via Tailscale](#secure-connection-via-tailscale) below.
- If something fails, see **Troubleshooting** below.

## Local mode (no Telegram)

Answer **2) Local** at the first setup question and Condor runs with **no Telegram bot at all**: no token, no `/web` login link, no polling. `make run` boots the process and the dashboard is at **http://localhost:8088**, already logged in. Everything else is the same product — portfolio, bots, agents, routines, trading — and notifications that would have gone to Telegram land in the dashboard's notification bell instead.

Use it for development, or to try Condor before deciding whether you want a bot.

> **Local mode has no login.** Anyone who can reach the port has full trading
> control. That is why it binds **`127.0.0.1` only** — the dashboard is reachable
> from the machine it runs on and nowhere else, not from your LAN and not from
> the internet.
>
> `WEB_HOST=0.0.0.0` in `.env` is the one, deliberate way to expose it. Only set
> it behind something that authenticates for you (Tailscale, an SSH tunnel, an
> authenticating reverse proxy). If you want Condor reachable from your phone,
> the answer is usually Telegram mode, not this.

The mode is **explicit** and is never guessed from whether a token is present: an
install configured for Telegram whose `TELEGRAM_TOKEN` goes missing **exits at
boot** telling you to run `make setup`. It never falls back to a login-less
dashboard.

Local mode logs in as `ADMIN_USER_ID` — the same id `config.yml`, your servers,
preferences and defaults already key on. `make setup` writes `ADMIN_USER_ID=1`
for an install that never had a Telegram id; an install that has one **keeps
it**, so switching modes keeps everything you had.

Switching later is a `make setup` re-run — it shows the current mode and offers
the other one — or editing `CONDOR_MODE` in `.env`. Your `TELEGRAM_TOKEN` is left
in place either way, so switching back is one line.

A mode that cannot work stops at boot, in `make run`, naming the `.env` line to
fix: telegram mode with no token, an `ADMIN_USER_ID` that is not a positive
integer, or a local user who is not in `config.yml`. None of it is deferred to
the browser.

## Commands

| Command | Description |
Expand Down Expand Up @@ -233,10 +269,15 @@ Preferences are automatically saved and persist across sessions:

### `.env`
```bash
TELEGRAM_TOKEN=your_bot_token
ADMIN_USER_ID=123456789
CONDOR_MODE=telegram # telegram (default) or local — see Local mode
TELEGRAM_TOKEN=your_bot_token # Required unless CONDOR_MODE=local
ADMIN_USER_ID=123456789 # Your Telegram user id. Local mode logs in
# as this same id (1 if you never had one)
OPENAI_API_KEY=sk-... # Optional, for AI features
OPENROUTER_API_KEY=sk-or-... # Optional, unlocks the OpenRouter LLM picker
WEB_HOST=0.0.0.0 # Optional. Overrides the dashboard bind
# address. Local mode binds 127.0.0.1;
# read the Local mode warning first.
```

> **OpenRouter:** Add `OPENROUTER_API_KEY` to `.env`, then in `/agent → Change LLM`
Expand Down Expand Up @@ -370,6 +411,8 @@ Both `condor` and `hummingbot-api` should appear as connected peers.
| Issue | Solution |
|-------|----------|
| Bot not responding | Check `TELEGRAM_TOKEN` and `ADMIN_USER_ID` in `.env` |
| Exits at boot: `TELEGRAM_TOKEN is not set` | Telegram mode needs a token. Run `make setup` — or choose Local mode there if you do not want a bot |
| Local mode: dashboard not reachable from another device | Intended — local mode binds `127.0.0.1`. See [Local mode](#local-mode-no-telegram) before changing `WEB_HOST` |
| Access pending | Admin must approve user via /config > Admin Panel |
| Commands failing | Verify Hummingbot API is running |
| Connection refused | Check server host:port in `/servers`; use `hummingbot-api` (not `localhost`) when API is on another machine via Tailscale |
Expand Down
74 changes: 0 additions & 74 deletions agents/backpack_mm/AGENT.md

This file was deleted.

Loading
Loading