The Claude Desktop JSON in the README rendered as one cramped line on the
package page — format it as a proper multi-line block. Bump version to
0.0.2 so the published package "About" picks up the fix.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add src/familiar/sde.py backing type lookups from a local SQLite SDE with
graceful fallback to ESI when absent. lookup.resolve_id prefers the SDE for
inventory_types; universe.get_item serves SDE-backed fields with no network
call. Register a read-only sde_status() MCP tool. Tested against an in-memory
SQLite fixture.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Invert the global write toggle so writes are ENABLED by default and the
user opts OUT, while keeping all other safety intact (per-call confirm=true
dry-run preview and the on-disk audit log are unchanged).
- writes.py: use a `writes_disabled` flag file instead of `writes_enabled`;
`writes_enabled()` returns True unless the flag exists (env var still
honored either way); `set_writes(False)` creates the flag, `set_writes(True)`
removes it. Update user-facing notes.
- tests: default is now ENABLED; adjust toggle/disabled tests (set disabled
explicitly via set_writes(False) or FAMILIAR_ENABLE_WRITES=0).
- README.md / CLAUDE.md: document writes are on by default, opt out via
`familiar writes disable`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EsiClient now caches GET responses honoring the Expires header and backs off
when the rolling ESI error window is nearly exhausted (X-Esi-Error-Limit-*).
README gains Setup / Connect-to-Claude / enabling-writes sections.
Closes#16. SDE bulk-load split out to its own follow-up (#51).
135 tests, coverage 90%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Document common commands, the register(mcp) tool-module pattern, the ESI/
auth/charutil/write-safety architecture, test conventions, and the dev-only
git/CI workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add read-only PI tools: get_planets (colonies), get_planet_layout
(pins/links/routes), get_corp_customs_offices. ESI exposes no PI write
endpoint despite the manage_planets scope name, so these are reads.
Closes#29. 132 tests, coverage 90%, 84 tools.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fleet: get_fleet (read, handles not-in-fleet); guarded invite_to_fleet and
update_fleet. UI: guarded set_waypoint and open_window (market/info/contract).
All writes go through write-safety.
Closes#27, #28. 128 tests, coverage 89%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contacts: read character/corp/alliance contacts; guarded add/remove of
character contacts. Fittings: read saved fits; guarded create/delete.
EsiClient.delete now takes params. All writes go through write-safety.
Closes#25, #26. 120 tests, coverage 89%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add read-only tools: faction-warfare stats (char + corp), freelance jobs
(char + corp), corp projects, character activities, and access lists.
FW endpoints are stable; the newer projects/freelance/activities/access
paths are best-effort and flagged for live confirmation.
Closes#34, #35, #36. 106 tests, coverage 91%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add read-only corp tools: members, member tracking, divisions, titles,
medals, standings (corp-level, need corp roles), plus the character's own
corp roles. Closes#32.
95 tests, coverage 91%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add read-only killmail tools: recent character and corp killmails (refs
enriched with system/victim/attacker detail) plus zKillboard PvP stats via
a tiny injectable zkill client. New charutil.character_targets helper for
token-less per-character iteration.
85 tests, coverage 93%. Closes#30.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add writes.py: the single gate every write tool must pass. A write happens
only when confirm=true AND writes are enabled (off by default); otherwise a
dry-run preview is returned. Every executed write is appended to an audit
log. New `familiar writes [enable|disable|status]` CLI and a read-only
write_status MCP tool.
81 tests, coverage 92%. Closes#22.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add read-only structure tools: search_structures (per character),
get_structure and get_structure_market (single structure via one token),
and get_corp container logs. New charutil.one_token helper picks a single
authenticated token (named character or first).
31 tools total, 75 tests, coverage 92%. Closes#21.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add read-only industry tools (industry jobs, blueprints, mining ledger;
corp jobs + blueprints) and trade tools (contracts, own market orders;
corp contracts + orders). New charutil helper runs a fetcher over one or
all characters, with a corp variant that resolves each character's corp id.
account._run now reuses it.
27 tools total, 70 tests, coverage 91%. Closes#18 and #19; covers most of #20.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Expand config.SCOPES to the complete character + corp scope set (64 read,
9 write), split into READ_SCOPES / WRITE_SCOPES so a caller can opt into a
read-only subset via FAMILIAR_SCOPES. Update the README: familiar is no
longer "read-only by design" — reads are free, writes are opt-in, previewed,
and audited.
Part of #17. Note: changing scopes requires re-running `familiar login` per
character to re-consent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rework the token store to hold many characters keyed by character_id,
migrating the previous single-character file transparently. `familiar login`
now adds a character; `familiar status` lists all; `familiar logout [name|id]`
removes one or all.
Every account tool gains an optional `character` (name or id): omitted means
all logged-in characters, given means just that one. Results are uniform
{"characters": [...]}. get_auth refreshes per character.
58 tests, coverage 89%. Closes#9
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The repo already has a REGISTRY_TOKEN secret (Gitea access token with
package scope); the workflow referenced a non-existent PACKAGE_REGISTRY_TOKEN
and fell back to the auto GITHUB_TOKEN, which is not granted package-write,
so every upload was rejected. Point twine at REGISTRY_TOKEN.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gitea's PyPI registry rejects twine's --skip-existing flag
(UnsupportedConfiguration), which failed every publish run. Remove it and
instead tolerate an "already exists" conflict in the shell, so dev (unique
.devN versions) always publishes and a main re-run of an existing release
is treated as success rather than a hard failure.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Setting `permissions: packages: write` alone dropped every other scope to
none, so actions/checkout could not clone the private repo and the publish
job failed before building. Add contents:read, and use github.actor (more
reliably populated than gitea.actor) as the twine username.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a thin async ESI client (httpx, descriptive User-Agent, uniform errors,
mockable transport) plus name<->id resolution. New read-only tools:
- universe: resolve_names, get_item, get_system, get_station, get_region, get_route
- market: list_hubs, get_market_price, get_market_orders, compare_hubs
Trade-hub IDs (Jita/Amarr/Dodixie/Rens/Hek) are hardcoded constants. Market
aggregation (best buy/sell, spread, order book) lives in pure helpers. 30 unit
tests with mocked ESI; coverage 99%. SDE bulk-load deferred to a later phase.
Closes#2
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lint (ruff) and test (pytest, fail under 80% coverage) on every PR and
push to main/dev. On a merge to main/dev, build the sdist+wheel and
publish to the Gitea PyPI registry — main as a clean release, dev as a
unique .devN pre-release. No Docker; runs on uv.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Set up the familiar package (src layout, uv/hatchling) with a FastMCP
server exposing a read-only ping health tool. Add pytest smoke tests with
80% coverage gate. Flesh out the README with the project vision and roadmap.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>