Python SDK & CLI 2.0

AnyMoment Python documentation

Create and manage recurring calendar events with natural language. anymoment and am are the same command. Requires Python 3.10 or newer.

Agents can drive AnyMoment through the CLI and the agent skill.

Features

Natural language event creation

Create complex recurring events from simple text.

Agenda with failures

Today, this week, and next week return events and failures together.

Machine-readable CLI

JSON, JSONL, field filters, dry run, profiles, and stable exit codes.

Structured errors

Exceptions carry a message, a next step, and a retry delay when the server sends one.

Installation

Python 3.10 or newer. Library only:

pip install anymoment

With the CLI:

pip install "anymoment[cli]"

CLI quick start

am is an alias for anymoment. today is today's agenda, week is this week, and next is next week. a is agenda, ls lists calendars, and rm deletes an event.

pip install "anymoment[cli]"

# Session token, or a non-interactive login
export ANYMOMENT_TOKEN="..."
am auth login --email you@example.com --password "$ANYMOMENT_PASSWORD"

am today
am week
am next
am today --json --fields events,failures
am agenda "tomorrow 3pm" --json

Library quick start

get_agenda returns events and failures together. If an older server still sends a plain list, those items are the events and there are no failures.

from anymoment import Client

client = Client(api_url="https://api.anymoment.sineways.tech", token="...")

result = client.get_agenda(
    start="2026-01-01T00:00:00Z",
    end="2026-01-31T23:59:59Z",
)
for item in result.events:
    print(item["event"]["name"], item["instances"])
for failure in result.failures:
    print(failure)

Migration from 1.x

Version 2.0.0 requires Python 3.10 or newer. Python 3.8 and 3.9 are no longer supported.

  • get_agenda returns an AgendaResult with .events and .failures. It is not a list. Read result.events.
  • delete_event and unlink_event_from_calendar return the response body. They no longer return None. Read .message and .sync_warnings.
  • update_event, update_event_from_text, toggle_event, and batch_remove_events_from_calendar return an object with .sync_warnings.
  • link_event_to_calendar returns an object with .link and .google_export_warnings.
  • Nested details, such as where an event came from, stay ordinary dictionaries you can read by field name.
  • Exceptions accept status_code, code, user_message, next_step, retry_after, details, and raw. message is the text to show.
  • New types: EmailNotVerifiedError when sign-in is blocked because the email is not verified, PermissionDeniedError (403), ConflictError (409), UnprocessableError (422), and RateLimitError (429, .retry_after). A server problem raises ServerError.
  • A response that succeeded, including one that is still finishing, does not raise an error.
  • A saved session refreshes itself when it expires. Signing in and extending a token do not refresh it, and a rejected calendar-server password does not either.
  • CLI exit codes are 0 ok, 2 usage, 3 auth, 4 not found, 5 conflict, 6 rate limited, 7 remote or sync error. A successful call that includes failures or sync_warnings still exits 0. Those fields are in the JSON payload.
  • --json and --jsonl are accepted on the subcommand. Errors with --json are one JSON object on stderr.

Configuration

Environment variables:

  • ANYMOMENT_BASE_URL default API URL (https://api.anymoment.sineways.tech)
  • ANYMOMENT_DEFAULT_CALENDAR default calendar ID
  • ANYMOMENT_DEFAULT_TIMEZONE default timezone
  • ANYMOMENT_TOKEN session token for non-interactive use. Login does not prompt.
  • ANYMOMENT_PROFILE config profile name. --profile sets the same value.
  • NO_COLOR turns terminal color off. A pipe does the same.

Config file: ~/.anymoment/config.json. A named profile uses ~/.anymoment/config.NAME.json.

export ANYMOMENT_TOKEN="..."
anymoment config set-url https://api.anymoment.sineways.tech
anymoment config set-timezone America/New_York
anymoment config set-calendar <calendar-id>
anymoment config show
am today --profile work

CLI commands

Authentication

Login does not prompt unless stdin is a terminal. Use ANYMOMENT_TOKEN or --email and --password for non-interactive use. auth resend-verification sends the verification email again.

anymoment auth login [--host URL]
anymoment auth login --email you@example.com --password "$ANYMOMENT_PASSWORD"
anymoment auth logout [--host URL]
anymoment auth resend-verification --json
anymoment tokens list
anymoment tokens clear

Calendars

anymoment calendars list [--active/--inactive] [--limit N] [--offset N]
anymoment calendars create <name> [--description TEXT] [--timezone TZ] [--color COLOR]
anymoment calendars get <id>
anymoment calendars update <id> [--name NAME] [--timezone TZ] [--color COLOR] [--active/--inactive]
anymoment calendars delete <id>
anymoment calendars share <id> <user-id> [--role ROLE]
anymoment calendars update-share <id> <user-id> --role ROLE
anymoment calendars unshare <id> <user-id>
anymoment calendars add-event <calendar-id> <event-id> [--display-order N] [--color COLOR]
anymoment calendars remove-event <calendar-id> <event-id>
anymoment calendars batch-add-events <calendar-id> <event-id> [<event-id> ...]
anymoment calendars batch-remove-events <calendar-id> <event-id> [<event-id> ...]
anymoment calendars webhook-url <id>
am ls

Events

anymoment events create "TEXT" [--name NAME] [--timezone TZ] [--calendar ID] [--model high|low|mega]
anymoment events list [--calendar ID] [--active/--inactive] [--limit N] [--offset N] [--minimal]
anymoment events get <id>
anymoment events update <id> [--name NAME] [--description TEXT]
anymoment events delete <id>
anymoment events toggle <id>
anymoment events instances <id> [--from DATE] [--to DATE] [--optimized]
anymoment events next <id>
anymoment events export <id> [--format ics|csv] [--from DATE] [--to DATE] [--out FILE]
anymoment events batch
am rm <event-id>

events batch reads JSONL operations from stdin. Filter events by date with events instances. On a terminal, delete asks first unless --yes is set.

Agenda

Agenda output is an object with events and failures. --fields events,failures keeps those fields, plus v.

am today
am week
am next
am today --json --fields events,failures
anymoment agenda "tomorrow 3pm"
anymoment agenda "next fri" --json
anymoment agenda list [--start ISO] [--end ISO] [--calendar ID] [--no-cache] [--webhooks]
anymoment agenda search <query> [--start ISO] [--end ISO] [--calendar ID] [--limit N] [--offset N]

Users

anymoment users me

Global flags

  • --json writes one compact JSON object on stdout ("v": 1).
  • --jsonl writes one compact JSON object per line.
  • --fields a,b keeps those JSON fields, plus v.
  • --dry-run shows a change without saving it. For a new event, this shows the result without creating it.
  • --yes skips the confirmation prompt. Delete on a terminal asks first unless this flag is set.
  • --profile NAME uses ~/.anymoment/config.NAME.json.
  • --idempotency-key KEY repeats the saved result of that command on this computer. The calendar service does not store the key.
  • --host, -h, --raw, --pipe, --timezone, -z, and --calendar, -c are also available.

With --json or --jsonl, errors are one JSON object on stderr: {"error": {"code", "status", "user_message", "next_step", "retry_after"}}.

Exit codes

  • 0 ok. A payload that includes failures or sync_warnings still exits 0.
  • 2 usage
  • 3 auth
  • 4 not found
  • 5 conflict
  • 6 rate limited
  • 7 remote or sync error

Schema and completion

anymoment schema prints the command list and exit codes as JSON. anymoment help --json prints the same document. anymoment completion prints a shell snippet for bash, zsh, or fish.

anymoment schema
anymoment help --json
anymoment completion bash
anymoment completion zsh
anymoment completion fish

Library API reference

from anymoment import Client

client = Client(api_url="https://api.anymoment.sineways.tech", token="optional-token")

Authentication

  • client.login(email, password)
  • client.refresh_token()
  • client.get_user_info()
  • client.resend_verification() sends the verification email again
  • client.signup(email, password, ...)

Calendars

  • client.list_calendars(...), get_calendar, create_calendar, update_calendar, delete_calendar
  • client.share_calendar(calendar_id, user_id, role)
  • client.update_calendar_share_role(calendar_id, user_id, role)
  • client.unshare_calendar(calendar_id, user_id)
  • client.get_calendar_webhook_url(calendar_id)

Events

  • client.list_events(...), get_event, create_event_from_text(recurrence_text, ...)
  • client.update_event and update_event_from_text return .sync_warnings
  • client.delete_event returns .message and .sync_warnings
  • client.toggle_event returns .sync_warnings
  • client.get_event_instances(event_id, from_date, to_date, optimized)
  • client.get_next_event_instance(event_id)

Agenda

client.get_agenda(start, end, calendar_ids=None, use_cache=True, include_webhooks=False) returns {events, failures}.

  • result.events is the agenda list
  • result.failures lists items the window could not load
  • client.search_events(q, start, end, calendar_ids, is_active, limit, offset, include_instances)

Calendar and event links

  • client.link_event_to_calendar(...) returns .link and .google_export_warnings
  • client.unlink_event_from_calendar(calendar_id, event_id) returns .message and .sync_warnings
  • client.batch_add_events_to_calendar(calendar_id, event_ids, ...)
  • client.batch_remove_events_from_calendar(calendar_id, event_ids) returns .sync_warnings

Error handling

Every exception exposes message, user_message, next_step, retry_after, code, status_code, details, and raw. Show message. Use next_step when it is set. RateLimitError.retry_after is the wait, in seconds, when the server sends one.

from anymoment import (
    AuthenticationError,
    EmailNotVerifiedError,
    PermissionDeniedError,
    NotFoundError,
    ConflictError,
    ValidationError,
    UnprocessableError,
    RateLimitError,
    ServerError,
)

try:
    client.login(email="user@example.com", password="secret")
except EmailNotVerifiedError as exc:
    print(exc.user_message)
    if exc.next_step:
        print(exc.next_step)
    client.resend_verification()
except RateLimitError as exc:
    print(exc.user_message, exc.retry_after)
except NotFoundError as exc:
    print(exc.message)
except ConflictError as exc:
    print(exc.user_message, exc.next_step)
except (AuthenticationError, PermissionDeniedError, ValidationError, UnprocessableError, ServerError) as exc:
    print(exc.message)

Support

By Sineways Technology. AnyMoment.