Metadata-Version: 2.4
Name: nostr-dev
Version: 1.0.0
Summary: Developer tooling for Nostr workflows.
Requires-Python: >=3.13
Requires-Dist: alembic
Requires-Dist: apscheduler
Requires-Dist: cryptography
Requires-Dist: httpx
Requires-Dist: keyring
Requires-Dist: nostr-sdk
Requires-Dist: pydantic-settings
Requires-Dist: rich
Requires-Dist: sqlmodel
Requires-Dist: structlog
Requires-Dist: tomli-w
Requires-Dist: typer
Description-Content-Type: text/markdown

# nostr-dev

Developer tooling for Nostr workflows: local key management, relay health checks, note
publishing, event querying, and GitHub-to-Nostr activity sync from the command line.

Status: MVP complete.

## Install

From a local checkout with `uv`:

```sh
uv sync
uv run nostr-dev --help
```

Install as a CLI in an isolated environment:

```sh
uv tool install .
nostr-dev --help
```

Or with `pipx`:

```sh
pipx install .
nostr-dev --help
```

## Architecture

```text
                 +---------------------------+
                 |        nostr-dev CLI      |
                 | Typer + Rich command UX   |
                 +-------------+-------------+
                               |
        +----------------------+----------------------+
        |                                             |
+-------v--------+                           +--------v-------+
| Local SQLite   |                           | SecretStore    |
| SQLModel       |                           | keyring first  |
| Alembic-ready  |                           | encrypted file |
+-------+--------+                           +--------+-------+
        |                                             |
        |                                             |
+-------v--------+       +--------------------+--------v-------+
| GitHub service |       | Nostr services     | RelayPool      |
| httpx API      |       | key/event/filter   | publish/query  |
| rate-limit UX  |       | builders           | nostr-sdk      |
+-------+--------+       +---------+----------+--------+-------+
        |                          |                   |
        v                          v                   v
   api.github.com             NIP-01 events       Nostr relays
```

## Command Reference

| Command | Purpose |
| --- | --- |
| `nostr-dev --version` | Print the installed version. |
| `nostr-dev --verbose` | Raise terminal log level to INFO. |
| `nostr-dev --debug` | Raise log level to DEBUG and show full tracebacks for unexpected errors. |
| `nostr-dev keygen [--show-secret] [--force]` | Generate a Nostr keypair, store the nsec in SecretStore, and store only npub metadata in SQLite. |
| `nostr-dev import [NSEC] [--force]` | Import an nsec from an argument or stdin. |
| `nostr-dev whoami` | Show the active npub. |
| `nostr-dev relay add URL` | Add a `wss://` relay. |
| `nostr-dev relay list` | List configured relays. |
| `nostr-dev relay ping [URL]` | Ping one relay or all active relays and record latency. |
| `nostr-dev relay remove URL [--yes]` | Remove a relay. |
| `nostr-dev publish "CONTENT"` | Publish a NIP-01 kind:1 note to all active relays. |
| `nostr-dev events [--author NPUB] [--kind K] [--limit N]` | Query active relays and print matching events. |
| `nostr-dev github login` | Validate and store a GitHub PAT. Reads `GITHUB_TOKEN` when set. |
| `nostr-dev github watch OWNER/REPO` | Validate and watch a GitHub repository. |
| `nostr-dev github list` | List watched repositories. |
| `nostr-dev github sync` | Fetch recent PRs, releases, and issues for watched repos, save new events, and publish them to Nostr when relays and a key are configured. |
| `nostr-dev github inbox [--all]` | Show locally stored GitHub events, unpublished by default. |
| `nostr-dev github opportunities [--label LABEL] [--repo OWNER/REPO]` | Live query for labeled open issues across watched repos. Does not publish or store notifications. |
| `nostr-dev github daemon` | Run scheduled GitHub sync using APScheduler and the configured sync interval. |

## Demo Walkthrough

### Day 1: Nostr toolkit

```console
$ nostr-dev keygen
Generated Nostr key:
npub1vwpkjqgdl6k6autnc7wmfdmmuf9

$ nostr-dev relay add wss://relay.damus.io
Added relay: wss://relay.damus.io

$ nostr-dev relay add wss://relay.primal.net
Added relay: wss://relay.primal.net

$ nostr-dev relay ping
                 Relay Ping
+-------------------------------------------+
| Relay                  | Status | Latency |
|------------------------+--------+---------|
| wss://relay.damus.io   | Online | 420 ms  |
| wss://relay.primal.net | Online | 515 ms  |
+-------------------------------------------+

$ nostr-dev publish "hello nostr, testing nostr-dev"
Event ID: a9368a716899e4c0de7cabdc359af05bde99bdf89034cfae263c9fbbc5aef4a8
2/2 relays confirmed
               Publish Results
+--------------------------------------------+
| Relay                  | Status   | Reason |
|------------------------+----------+--------|
| wss://relay.damus.io   | accepted | -      |
| wss://relay.primal.net | accepted | -      |
+--------------------------------------------+

$ nostr-dev events --author npub1vwpkjqgdl6k6autnc7wmfdmmuf9 --kind 1 --limit 5
                                 Nostr Events
+-----------------------------------------------------------------------------+
| Author                | Kind | Created               | Content              |
|-----------------------+------+-----------------------+----------------------|
| npub1vwpkjqgdl6k6aut… | 1    | 2026-07-11T22:02:38+… | hello nostr, testing |
|                       |      |                       | nostr-dev            |
+-----------------------------------------------------------------------------+
```

### Day 2: GitHub workflows

```console
$ GITHUB_TOKEN=github_pat_redacted nostr-dev github login
Authenticated as octocat

$ nostr-dev github watch bitcoin/bitcoin
Watching bitcoin/bitcoin

$ nostr-dev github watch rust-nostr/nostr
Watching rust-nostr/nostr

$ nostr-dev github sync
3 new events found, 3 published to Nostr

$ nostr-dev github inbox --all
                                GitHub Inbox
+-----------------------------------------------------------------------------+
| Repo            | Type         | Title                     | Published | Created |
|-----------------+--------------+---------------------------+-----------+---------|
| bitcoin/bitcoin | pull_request | PR #35120 Improve package | yes       | 2026-… |
| rust-nostr/nostr| release      | Release v1.0.0            | yes       | 2026-… |
+-----------------------------------------------------------------------------+

$ nostr-dev github opportunities
                 GitHub Opportunities: bitcoin/bitcoin
+-----------------------------------------------------------------------------+
| Issue | Title                         | Label            | URL                  |
|-------+-------------------------------+------------------+----------------------|
| #315  | Add focused relay smoke tests | good first issue | https://github.com/… |
+-----------------------------------------------------------------------------+

$ nostr-dev github opportunities --repo rust-nostr/nostr --label "help wanted"
                 GitHub Opportunities: rust-nostr/nostr
+-----------------------------------------------------------------------------+
| Issue | Title                         | Label       | URL                  |
|-------+-------------------------------+-------------+----------------------|
| #42   | Improve subscription examples | help wanted | https://github.com/… |
+-----------------------------------------------------------------------------+
```

Run recurring GitHub sync as a long-lived process:

```sh
nostr-dev github daemon
```

The daemon uses `NOSTR_DEV_SYNC_INTERVAL_SECONDS` and stores scheduler jobs in the same
SQLite database.

## Configuration

`nostr-dev` reads non-secret config from environment variables prefixed with
`NOSTR_DEV_` and from `~/.nostr-dev/config.toml`. Environment variables win.

Useful variables:

| Variable | Purpose |
| --- | --- |
| `GITHUB_TOKEN` | Optional PAT source for `nostr-dev github login`. |
| `NOSTR_DEV_DB_PATH` | Override the SQLite database path. |
| `NOSTR_DEV_GITHUB_API_BASE_URL` | Override the GitHub API base URL. |
| `NOSTR_DEV_SYNC_INTERVAL_SECONDS` | Scheduler interval for `github daemon`. |
| `NOSTR_DEV_OPPORTUNITY_LABELS` | Default labels for `github opportunities`. |
| `NOSTR_DEV_SECRET_BACKEND` | Force `keyring` or `file` secret storage. |

## Testing

Default tests are unit tests only:

```sh
uv run pytest
uv run ruff check .
uv run mypy src
```

Integration tests require Docker and a local nostr-rs-relay:

```sh
docker compose up -d
uv run pytest -m integration
```

The local relay is exposed at `ws://127.0.0.1:7777`. Override it with
`NOSTR_DEV_INTEGRATION_RELAY_URL`.

## Security Notes

- Secret values are never logged intentionally.
- `nostr-dev keygen` and `nostr-dev import` store nsec values in SecretStore, not SQLite.
- `nostr-dev whoami`, `publish`, `events`, GitHub commands, and sync output never print nsec
  values.
- `nostr-dev keygen --show-secret` is the only command path that prints a newly generated
  nsec, and it asks for confirmation first.
- GitHub PATs are read from `GITHUB_TOKEN` or an interactive prompt, validated, then stored
  in SecretStore.
- The OS keychain backend is preferred. The encrypted-file backend is a compatibility
  fallback protected by a passphrase-derived Fernet key. It is best-effort local protection,
  not HSM-grade storage.
- Relay publishing is public by design. Do not publish sensitive content to Nostr relays.

## Non-Goals

- Multi-identity workflows. The MVP assumes a single active key.
- NIP-65 relay discovery.
- A web UI.
- HSM-grade secret storage for the encrypted-file backend.
- Running a production Nostr relay.
- Replacing GitHub notification systems; sync is intentionally small and explicit.
