Skip to content

ContextVM/fleetgner

Repository files navigation

fleetgner

fleetgner is a delegated Nostr signer that runs as an MCP server over ContextVM (CVM).

It lets an admin grant specific users permission to request signatures from specific keys, with optional policies that constrain what can be signed.

It exposes two interfaces:

  • NIP-46 for existing Nostr clients that already speak remote-signing
  • CVM/MCP tools for agents and users that want an ergonomic RPC tool surface

In both cases, the same grant and policy enforcement applies through SigningCore.signDraft().

Why

Nostr signing is powerful and dangerous. A signer that is always-on, shared, or remotely reachable needs explicit access control.

fleetgner exists to make delegated signing:

  • Remote — users connect over relays
  • Auditable — access decisions are explicit: user, key, grant, policies
  • Composable — policies can be added and extended over time
  • Simple — the prototype favors a small RPC surface with predictable semantics

High-level architecture

  • Transport: ContextVM uses Nostr as the transport for MCP-style JSON-RPC messages. The server is started in index.ts.
  • CVM tool layer: tools are registered in createFleetgnerMcpServer().
  • NIP-46 gateway: NIP-46 connections are managed by Nip46Gateway.
  • Authorization: signing is allowed only when the caller is an enabled user, the target key is enabled, the grant is enabled, and all enabled policies accept the draft in SigningCore.
  • Persistence: state lives in SQLite tables defined in src/db/schema.ts.

Core mental model

The prototype is intentionally built around a few simple concepts.

Users

A user is a caller pubkey that may be allowed to use one or more signing keys.

Keys

A key is a signing identity imported into the server keyring.

Grants

A grant binds one user to one key.

  • Managed through "grant_set" and "grant_remove"
  • Grants are enabled by default unless explicitly disabled via the disable input
  • allow_unrestricted is false by default

This means a newly enabled zero-policy grant is rejected unless the admin explicitly opts in to unrestricted access.

Policies

Policies are optional restrictions attached to a grant.

Important semantics:

  • If a grant has one or more policies, allow_unrestricted becomes irrelevant for effective authorization
  • If a grant has zero policies, unrestricted signing is only allowed when allow_unrestricted was explicitly set

Connections

Connections are transport/session metadata for NIP-46 access.

Connections are not the authorization model. They are just the communication layer on top of users, keys, grants, and policies.

Operator workflow

The recommended onboarding flow for this prototype is:

  1. Create or update the user with "user_set"
  2. Import or choose a signing key with "key_import" / "key_update"
  3. Create a grant with "grant_set"
  4. Add one or more policies with "policy_set", unless unrestricted access is truly intended
  5. Create a connection if the user needs NIP-46 access

All mutation tools use disable for boolean state changes. Omit it to keep the current/default enabled state.

Safe grant creation

Safe-by-default behavior is one of the main prototype design goals.

For "grant_set":

  • disable defaults to omitted, which means the grant stays enabled by default
  • allow_unrestricted defaults to false
  • a restricted zero-policy grant can be created first, before policies are added
  • signing remains blocked until at least one policy exists, unless allow_unrestricted: true

This keeps onboarding natural while still preventing accidental full-access grants.

Read tools

Lists visible users.

  • Admin sees all users
  • The configured admin always sees itself in the list, even if it was not created as a user row
  • Non-admin sees only self
  • By default returns users with labels, grants, and policies
  • Use include_connections: true to also include connection metadata

Admin-only detailed lookup for one user.

  • Returns a full user record including label, grant metadata, and connections
  • Intended for targeted inspection without listing every user in detail

Admin-only listing of imported signing keys.

NIP-46 behavior

NIP-46 connections are restored at startup by restoreNip46Connections().

The current prototype also tracks restore failures in nip46_connections.restore_failure_count.

Connections are stopped when their backing authorization state is no longer valid, and restarted when authorization becomes valid again, including after user/key/grant/policy state changes.

Invalid authorization states include:

  • disabled users
  • disabled keys
  • disabled or removed grants
  • policy changes that alter the effective signing rules

This behavior is implemented in Nip46Gateway.

Built-in policy types

The first prototype ships with a small built-in set in BUILTIN_POLICIES:

  • allow_kinds
  • deny_kinds
  • expires_at
  • max_content_length
  • require_tag

These are intentionally simple and meant to cover the initial safety/ergonomics tradeoffs.

Run

Install

bun install

Configure

Set environment variables used by main():

  • FLEETGNER_ADMIN_PUBKEY — admin pubkey allowed to manage users, grants, policies, and keys
  • FLEETGNER_SERVER_NSEC_OR_HEX — server identity key for the CVM transport
  • FLEETGNER_RELAYS — comma-separated relay URLs, default wss://relay.contextvm.org
  • FLEETGNER_DB_PATH — SQLite file path, default fleetgner.sqlite

Start

bun run index.ts

Development

Useful commands from the repository root:

bun test
bun run build
bun run format

The current automated coverage focuses on repositories, bootstrap behavior, and signing core behavior in test/fleetgner-core.test.ts and test/bootstrap.test.ts.

Prototype status

This repository is currently a first prototype.

That means:

  • schema changes are still allowed
  • clean refactors are preferred over compatibility workarounds
  • UX consistency and safety semantics are being actively refined

The main product goal for this iteration is to keep the implementation tight, simple, and straightforward while proving the delegated signing model end to end.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors