Skip to content

CLI

Fulcra provides an easy to use command line interface suitable for use by both humans and agents.

Installation

The fulcra CLI command is included with the fulcra-api package in PyPI.

This is a Python module, so the most straightforward way to get started using it is by using a tool like uvx or pipx to run it directly:

Via uv/uvx:

uvx fulcra-api --help

Via pipx:

pipx run fulcra-api --help

If you're working in an existing Python environment/project, you can install fulcra-api directly (e.g. with uv add fulcra-api or pip install fulcra-api).

Usage

Interactive documentation is available via fulcra --help:

> fulcra --help
Usage: fulcra [OPTIONS] COMMAND [ARGS]...

  Command line interface for authenticating and interacting with the Fulcra
  Life API.

  Sub-commands return JSON data by default for convienent piping into tools
  like `jq` for parsing and filtering.

Options:
  --beta  Enable beta features
  --help  Show this message and exit.

Commands:
  apple-location-updates   Return Apple location update records
  apple-location-visits    Return Apple location visit records
  apple-workouts           Return Apple workouts
  auth                     Authentication sub-commands
  calendar-events          Return Apple calendar events
  calendars                Return Apple calendars
  catalog                  Return a list of queryable Fulcra data types and
                           metadata
  data-type                Data type management sub-commands
  data-updates             Return data/file updates that occurred during a
                           period
  delete                   Delete records for a data type
  file                     File management sub-commands
  get-records              Return raw sample records for a data type
  google-location-updates  Return Google Maps location update records
  location-at-time         Return location at specified time
  location-time-series     Return a calculated time series of location data
  metric-time-series       Return a calculated time series for a metric
  record                   Record data for a data type
  share                    Data sharing management sub-commands
  sleep-cycles             Return sleep cycles summarized from sleep stages
  sleep-cycles-aggregated  Return sleep cycles aggregated by a specific period
  sleep-stages             Return sleep stages derived from sleep-related
                           metric records
  tag                      Tag management sub-commands
  user-info                Return information about the authenticated user

All fulcra commands also have detailed documentation via the --help flag.

Authentication

Most CLI commands require authentication to the Fulcra Platform. At a terminal, running fulcra auth login will return a URL (as well as opening a browser window to that URL if supported) for users to authenticate or sign up with Fulcra. This command will automatically complete once authentication is finished and save the access credentials for the session to disk.

When fulcra auth login isn't run at a terminal (for example by an AI agent, from a script, or with its output piped), it doesn't wait. It prints the URL, the code and a device code, then exits, as --get-auth-url does. Add --wait to wait for approval anyway.

Agents authenticate users in two steps. Run fulcra auth login --get-auth-url to return a URL and code, and show them to the user in your reply before doing anything else. Then run the fulcra auth login --device-code <device code> command it prints, which waits until the user has finished logging in.

Example:

> fulcra auth login --get-auth-url
Open the web auth URL in a browser, verify the web auth code, and complete the web auth flow.

Web auth URL: https://fulcra.us.auth0.com/activate?user_code=MTJJ-NFDF
- Web auth code: MTJJ-NFDF
- Device code: 7dxrpM_971s4p-WGy2Cs3TUW

After finishing the web auth flow, complete authentication with the device code by running:

fulcra-api auth login --device-code 7dxrpM_971s4p-WGy2Cs3TUW --poll-timeout 900 --poll-interval 5

Finding Data Types In The Catalog

Find Data Types you can query or record via the catalog with the fulcra catalog command.

> fulcra catalog
{"id": "MomentAnnotation", "name": "MomentAnnotation", "column_name": "moment", "api_version": "v1alpha1", "description": "Base event type that records a single point in time", "categories": ["annotations", "base_type"], "record_spec": {"type": "event"}, "queryable": true, "recordable": true, "icon": null, "deprecated": false, "fulcra_userid": "ce69505f-fe57-49d4-b3f4-2d52c51eedee", "class": "event", "related_cli_commands": ["get-records"]}
{"id": "DurationAnnotation", "name": "DurationAnnotation", "column_name": "duration", "api_version": "v1alpha1", "description": "Base event type that records a span of time", "categories": ["annotations", "base_type"], "record_spec": {"type": "event"}, "queryable": true, "recordable": true, "icon": null, "deprecated": false, "fulcra_userid": "ce69505f-fe57-49d4-b3f4-2d52c51eedee", "class": "event", "related_cli_commands": ["get-records"]}
{"id": "BodyAwareness", "name": "Body Awareness", "column_name": "moment", "api_version": "v1alpha1", "description": "Recording of a moment in time regarding body awareness", "categories": ["annotations", "mindfulness"], "record_spec": {"type": "event"}, "queryable": true, "recordable": true, "icon": null, "deprecated": false, "fulcra_userid": "ce69505f-fe57-49d4-b3f4-2d52c51eedee", "class": "event", "related_cli_commands": ["get-records"]}
{"id": "Intuition", "name": "Intuition", "column_name": "moment", "api_version": "v1alpha1", "description": "Recording of a moment in time regarding intuition", "categories": ["annotations", "mindfulness"], "record_spec": {"type": "event"}, "queryable": true, "recordable": true, "icon": null, "deprecated": false, "fulcra_userid": "ce69505f-fe57-49d4-b3f4-2d52c51eedee", "class": "event", "related_cli_commands": ["get-records"]}
...

Most query commands return objects as JSON lines, which can be piped into other tools like jq for display and filtering.

This returns all data types in the Fulcra platform, your own custom data types, and any data types that have been shared with you by other users.

To list only the data types you and other users have created, use --user-defined. Add --recordable for only your own, or --user-id <user ID> for the ones one person shares with you.

> fulcra catalog --user-defined
{"id": "MomentAnnotation/64e12302-8463-465d-b4c3-ea42f3290561", "name": "Headache", "column_name": "moment", "api_version": "v1alpha1", "description": "Track when I have a headache", "categories": ["user_configured", "user_defined"], "record_spec": {"type": "event"}, "queryable": true, "recordable": true, "icon": null, "deprecated": false, "fulcra_userid": "ce69505f-fe57-49d4-b3f4-2d52c51eedee", "class": "event", "related_cli_commands": ["get-records"]}
{"id": "MomentAnnotation/92e276e0-a894-4ebf-8f8f-4db9c91b37cd", "name": "Workout", "column_name": "moment", "api_version": "v1alpha1", "description": "Track when I've done a workout", "categories": ["user_configured", "user_defined"], "record_spec": {"type": "event"}, "queryable": true, "recordable": true, "icon": null, "deprecated": false, "fulcra_userid": "ce69505f-fe57-49d4-b3f4-2d52c51eedee", "class": "event", "related_cli_commands": ["get-records"]}
...

Data Types are also categorized and can be filtered with the -c option, e.g. fulcra catalog -c base_type for the base types you can build your own data types on.

Writing Records

Specific data types can be recorded to Fulcra via the fulcra record command.

You can record a single sample explicitly via command line arguments. Arguments differ depending on the type of record associated with the given data type.

# Record an event
> fulcra record MomentAnnotation/64e12302-8463-465d-b4c3
Recorded 1 record to MomentAnnotation
Upload ID: 484bf823-9d1a-4713-ba1c-53bcbf342da0
# Record a metric value
> fulcra record NumericAnnotation/642f37c8-67aa-4758-8cc9-9368b47dd766 50
Recorded 1 record to NumericAnnotation
Upload ID: 210c9bcf-e946-4335-87a2-f122a289c580

Multiple records can be recorded for a data type by passing a file with the -f option, or via pipes.

> fulcra record NumericAnnotation/642f37c8-67aa-4758-8cc9-9368b47dd766 -f measurements.json
Recorded 2 records to NumericAnnotation
Upload ID: 54c7a91d-8769-4938-bdfa-ba9f9c755454

# Pipe records into fulcra record
> cat measurements.json
{"value": 34, "recorded_at": "2025-06-03T00:10:04Z"}
{"value": 600, "recorded_at": "2025-06-03T00:10:06Z"}
> cat measurements.json | fulcra record NumericAnnotation/642f37c8-67aa-4758-8cc9-9368b47dd766
Recorded 2 records to NumericAnnotation
Upload ID: 54c7a91d-8769-4938-bdfa-ba9f9c755454
Files must be formatted as JSON lines with each record on an individual line. Record schema for data types is published as JSON Schema.

# Return the record schema for a data type
> fulcra data-type schema NumericAnnotation/642f37c8-67aa-4758-8cc9-9368b47dd766
{
  "properties": {
    "id": {
      "anyOf": [
        {
          "format": "uuid",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Record ID. [Default: generated]",
      "title": "Id"
    },
    "tags": {
      "anyOf": [
        {
          "items": {
            "format": "uuid",
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Record Tags",
      "title": "Tags"
    },
    "sources": {
      "anyOf": [
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Record Source",
      "title": "Sources"
    },
    "value": {
      "description": "Record Value",
      "title": "Value",
      "type": "number"
    },
    "unit": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Unit description",
      "title": "Unit"
    },
    "recorded_at": {
      "anyOf": [
        {
          "format": "date-time",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Recorded at timestamp in ISO 8601 format [Default: now]",
      "title": "Recorded At"
    },
    "note": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Note"
    }
  },
  "required": [
    "value"
  ],
  "title": "RecordSchema",
  "type": "object"
}

Querying Records

Records for a data type can be returned via fulcra get-records.

Records aligned across a time span like Events and Metrics can be queried relatively (15 minutes, 1 hour, 1 month) or within a range of specific timestamp value.

# Return all headache events in the last week
> fulcra get-records MomentAnnotation/64e12302-8463-465d-b4c3-ea42f3290561 "1 week" | jq -r '.recorded_at'
2026-07-23T20:48:59.63747+00:00
# Return all energy level recordings over a window of time
> fulcra get-records EnergyLevel "2025-05-27T03:03:00Z" "2025-05-27T09:43:00Z" | jq -r '[.recorded_at, .value] | join(": ")'
2025-05-27T03:38:33.316468+00:00: 3
2025-05-27T04:40:03.857382+00:00: 4 
2025-05-27T06:18:43.172374+00:00: 8 
2025-05-27T08:48:58.734832+00:00: 7 

Creating Data Types

If you want to record things not already in the Fulcra Catalog, you can create your own data types with fulcra data-type create.

# Find base types in the catalog
> fulcra catalog -c base_type | jq -r '"\(.id) (type: \(.record_spec.type)) -- \(.description)"'
MomentAnnotation (type: event) -- Base event type that records a single point in time
DurationAnnotation (type: event) -- Base event type that records a span of time
NumericAnnotation (type: metric) -- Base metric type to record a numeric value
ScaleAnnotation (type: metric) -- Base metric type to record a numeric value on a given scale
BooleanAnnotation (type: metric) -- Base metric type to record a boolean (true/false) value
# Create a metric to track my headaches
> fulcra data-type create MomentAnnotation Headaches --description "Tracks whenever I get a headache"
{"name": "Headaches", "description": "Tracks whenever I get a headache", "annotation_type": "moment", "measurement_spec": null, "spec": null, "tags": [], "fulcra_userid": "ce69505f-fe57-49d4-b3f4-2d52c51eedee", "id": "eb647da3-f789-41c2-912d-57e525978ae7", "created_at": "2026-07-23T21:56:52.900080Z", "updated_at": "2026-07-23T21:56:52.900080Z", "deleted_at": null, "fulcra_source_id": "com.fulcradynamics.annotation.eb647da3-f789-41c2-912d-57e525978ae7"}

User defined data types can then be referenced by their catalog ID in <BaseType>/<UUID> format.

> fulcra catalog -n Headaches | jq -r '.id'
MomentAnnotation/eb647da3-f789-41c2-912d-57e525978ae7

This identifier can be used like any other data type identifier in fulcra record and fulcra get-records

Event and Metric data types with custom fields

For new tracking, base your data type on Event (something that happens, at a point in time or over a range) or Metric (a measured number). Unlike the annotation types above, these can carry fields of your own: pass them as a JSON Schema to --fields. A description is required.

# An event with its own fields; "mood" must always be given
> fulcra data-type create Event "Check-ins" --description "How I'm feeling" \
    --fields '{"properties": {"mood": {"type": "string"}, "energy": {"type": "integer", "minimum": 1, "maximum": 5}}, "required": ["mood"]}' \
    | jq -r '.id'
Event/A0E15CC7-5BBA-4F8B-A7C6-DE4E6EE07AA3

# Record it: field options set the custom fields
> fulcra record Event/A0E15CC7-5BBA-4F8B-A7C6-DE4E6EE07AA3 --mood=calm --energy=4

# A metric with a unit
> fulcra data-type create Metric "Caffeine" --description "Caffeine I've had" --unit mg --aggregation cumulative

Records are checked against the data type's fields before they're uploaded, and a record that breaks a rule is refused with the reason. fulcra data-type schema <ID> shows a data type's fields.

fulcra data-type list lists the data types you have created (archived ones aren't listed). Add --include-shared to include ones others share with you, --api-version to limit it to one API version, or --name to filter by name.

> fulcra data-type list | jq -r '"\(.id) -- \(.name)"'
MomentAnnotation/eb647da3-f789-41c2-912d-57e525978ae7 -- Headaches

Archiving data types

fulcra data-type archive hides a data type you no longer use, and fulcra data-type restore brings it back with its records. Both take the full ID as the catalog shows it, such as Event/<UUID> or MomentAnnotation/<UUID>. Built-in data types can't be archived.

> fulcra data-type archive Event/A0E15CC7-5BBA-4F8B-A7C6-DE4E6EE07AA3
Archived data type: Event/A0E15CC7-5BBA-4F8B-A7C6-DE4E6EE07AA3
> fulcra data-type restore Event/A0E15CC7-5BBA-4F8B-A7C6-DE4E6EE07AA3 | jq -r '.id'
Event/A0E15CC7-5BBA-4F8B-A7C6-DE4E6EE07AA3

Data Updates

The fulcra data-updates command will return a summary of updated data over a time span. This can be useful for loops where agents can be informed of what data types have been recorded recently.

# Return summary of data types and files written to Fulcra in the last hour
> fulcra data-updates "1 hour" | jq
{
  "data_types": {
    "EnergyLevel": 1
  },
  "file_changes": [
    {
      "id": "0860a5dc-278b-4114-854a-06dba59f1ae8",
      "full_name": "/example.json",
      "scan_state": "unscanned",
      "last_scanned": null,
      "size": 3,
      "uploaded_at": "2026-07-23T21:21:18.476239Z",
      "archived_at": null,
      "deleted_at": null,
      "state": "uploaded"
    }
  ]
}

To also check everyone who shares data with you, add --include-shared. Each person with updates appears under shared, keyed by their user ID, with their name and the Data Types and files they share with you that changed. Use --user-id <user ID> instead to check one person.

> fulcra data-updates "1 hour" --include-shared | jq '.shared'

Updates are counted by when Fulcra processed each record, and the counts appear a few minutes after the records can be read. To catch everything since a previous check, start the time span a little before that check.

Messages To Other People's Agents

fulcra connection send sends a message to another person's agent over a connection made with the connect-our-agents skill. Each person in a connection has a channel, an Event Data Type that they share with the others, and a message is a record on your own channel.

The message text is read from stdin as plain text, with no JSON and no escaping. A heredoc with a quoted delimiter (<<'MSG') keeps the shell from changing anything in it. Name the connection by your channel's ID (Event/<UUID>), or by the other person's Fulcra user ID when exactly one of your channels is shared with them. --as is your agent's name; use the same one every time.

> fulcra connection send <user ID> --as alice-claude --topic dinner <<'MSG'
Dinner Friday? It's "7pm" at Joe's.
MSG
{"id": "34422f93-b132-4330-a7ae-c43ca6f04abe", "channel": "Event/1c801972-2766-4783-8693-41b01c786a55", "upload_id": "...", "sender": "alice-claude", "kind": "message", "body": "Dinner Friday? It's \"7pm\" at Joe's.", "topic": "dinner"}

To answer one of their messages, pass its id with --reply-to, or with --ack to say you've read it before you can answer. The ID is checked against their channel over the last 30 days, and acks can't be answered. A reply or ack without --topic reuses the topic of the message it answers. --for <agent name> addresses only some of the agents in a connection, and --priority takes P1, P2 or P3.

The command prints the message as sent, including its id. If you can't tell whether a send went through, run it again with --id <that id>: a message sent again with the same id is stored once. Nothing is sent if a check fails.

Files

The Fulcra CLI can manage files in your Fulcra datastore via the fulcra file subcommand.

Remote paths are always written with forward slashes and are rooted at / (for example /team/demo/role.md), regardless of the platform the CLI runs on. A path without a leading / is treated as relative to the root.

# Upload a file to Fulcra
> fulcra file upload example.json
⬆️ example.json -> fulcra:/example.json
# List files in Fulcra
> fulcra file list
2KiB      2026-07-23 09:21PM UTC  example.json
# Download a file from Fulcra
> fulcra file download example.json
⬇️ fulcra:/example.json -> example.json 
# Print the contents of a file in Fulcra
> fulcra file download example.json -
{"description": "example data"}