Skip to main content

AnyMoment Python SDK & CLI

Python SDK and command-line interface for the AnyMoment API - Create and manage recurring calendar events with natural language.

📖 Full documentation (Python SDK & CLI) — installation, quick start, all CLI commands, and Library API reference.

Features

  • 🎯 Natural Language Event Creation - Create complex recurring events from simple text
  • 📅 Full Calendar Management - Create, update, delete, and share calendars
  • 🔐 Secure Token Management - Encrypted token storage with automatic refresh
  • 🚀 Both Library & CLI - Use programmatically or from the command line
  • ⚡ Fast & Reliable - Built on requests with proper error handling

Installation

Library Only

pip install anymoment

With CLI

pip install anymoment[cli]

Quick Start

CLI Usage

# Login
anymoment auth login

# Create a calendar
anymoment calendars create "Work Calendar" --timezone "America/New_York"

# Create an event from natural language
anymoment events create "Weekly team meeting every Monday at 10 AM" \
    --calendar <calendar-id>

# List events
anymoment events list --calendar <calendar-id>

# Get event instances for a date range
anymoment events instances <event-id> --from "2026-01-01" --to "2026-03-31"

Library Usage

from anymoment import Client

# Initialize client
client = Client(api_url="https://api.anymoment.sineways.tech")

# Login
client.login(email="user@example.com", password="secret")

# Create calendar
calendar = client.create_calendar(
    name="Work Calendar",
    timezone="America/New_York"
)

# Create event from natural language
event = client.create_event_from_text(
    recurrence_text="Weekly team meeting every Monday at 10 AM",
    calendar_id=calendar["id"]
)

# Get event instances for a date range
instances = client.get_event_instances(
    event_id=event["id"],
    from_date="2026-01-01",
    to_date="2026-03-31"
)

Version 2.0

get_agenda returns an object with .events and .failures. Delete, unlink, update, toggle, and link return their warning fields instead of dropping the response body. Errors expose user_message, next_step, code, and retry_after. The migration notes are in CHANGELOG.md.

anymoment agenda "next week" --json
anymoment auth login --email you@example.com --password "$ANYMOMENT_PASSWORD"
# or skip the prompt with ANYMOMENT_TOKEN
anymoment schema

anymoment and am are the same command. a is agenda, ls lists calendars, and rm deletes an event.

Configuration

Environment Variables

  • ANYMOMENT_BASE_URL - Default API base URL (default: https://api.anymoment.sineways.tech)
  • ANYMOMENT_DEFAULT_CALENDAR - Default calendar ID
  • ANYMOMENT_DEFAULT_TIMEZONE - Default timezone
  • ANYMOMENT_TOKEN - Session token for non-interactive use. No login prompt.
  • ANYMOMENT_PROFILE - Config profile name (--profile sets the same value)
  • NO_COLOR - Disable terminal color

Config File

Configuration is stored in ~/.anymoment/config.json. You can manage it via CLI:

# Set default API URL
anymoment config set-url https://api.anymoment.sineways.tech

# Set default timezone
anymoment config set-timezone America/New_York

# Set default calendar
anymoment config set-calendar <calendar-id>

# Show current config
anymoment config show

CLI Commands

Authentication

# Login interactively
anymoment auth login [--host URL]

# Logout (clear token)
anymoment auth logout [--host URL]

# Non-interactive login
anymoment auth login --email you@example.com --password "$ANYMOMENT_PASSWORD"
# or export ANYMOMENT_TOKEN

# Send the verification email again
anymoment auth resend-verification --json

# List all tokens
anymoment tokens list

# Clear all tokens
anymoment tokens clear

Calendars

# List calendars
anymoment calendars list [--active/--inactive] [--limit N] [--offset N]

# Create calendar
anymoment calendars create <name> [--description TEXT] [--timezone TZ] [--color COLOR]

# Get calendar details
anymoment calendars get <id>

# Update calendar
anymoment calendars update <id> [--name NAME] [--description TEXT] [--timezone TZ] [--color COLOR] [--active/--inactive]

# Delete calendar
anymoment calendars delete <id>

# Share calendar with another user (set role: owner, editor, viewer)
anymoment calendars share <id> <user-id> [--role ROLE]

# Update a shared user's role
anymoment calendars update-share <id> <user-id> --role ROLE

# Remove share (user loses access unless linked via Google)
anymoment calendars unshare <id> <user-id>

# Add / remove events to or from a calendar (link or unlink)
anymoment calendars add-event <calendar-id> <event-id> [--display-order N] [--color COLOR]
anymoment calendars remove-event <calendar-id> <event-id>

# Batch add or remove events to or from a calendar
anymoment calendars batch-add-events <calendar-id> <event-id> [<event-id> ...] [--display-order N] [--color COLOR]
anymoment calendars batch-remove-events <calendar-id> <event-id> [<event-id> ...]

# Get webhook URL
anymoment calendars webhook-url <id>

Events

# Create event from natural language
anymoment events create "TEXT" [--name NAME] [--description TEXT] [--timezone TZ] [--calendar ID] [--model MODEL]

# List events
anymoment events list [--calendar ID] [--active/--inactive] [--limit N] [--offset N] [--minimal]

Note: To filter events by date range, use `events instances` instead.

# Get event details
anymoment events get <id>

# Update event
anymoment events update <id> [--name NAME] [--description TEXT]

# Delete event
anymoment events delete <id>

# Toggle event active status
anymoment events toggle <id>

# Get event instances
anymoment events instances <id> [--from DATE] [--to DATE] [--optimized]

# Get next instance
anymoment events next <id>

# Export instances
anymoment events export <id> [--format ics|csv] [--from DATE] [--to DATE] [--out FILE]
# One call. Prints the resolved UTC window, then the events.
anymoment agenda "tomorrow 3pm"
anymoment agenda "next fri" --json
anymoment today
anymoment week
anymoment next

# List events and instances in a time window (agenda)
anymoment agenda list [--start ISO] [--end ISO] [--calendar ID] [--no-cache] [--webhooks]

# Fuzzy search events by name (optional time window and filters)
anymoment agenda search <query> [--start ISO] [--end ISO] [--calendar ID] [--active/--inactive] [--limit N] [--offset N] [--no-instances]

Users

# Show current user info
anymoment users me

Common Options

  • --host, -h URL - Override API host URL (env: ANYMOMENT_BASE_URL)
  • --raw - Output full JSON response
  • --pipe - Output only IDs (for piping/chaining)
  • --json - One compact JSON object on stdout ("v": 1)
  • --jsonl - One compact JSON object per line
  • --fields a,b - Keep these JSON fields, plus v
  • --dry-run - Show a mutation without sending it. Create uses the preview endpoint.
  • --idempotency-key KEY - Local replay cache. The API has no idempotency header.
  • --profile NAME - Use ~/.anymoment/config.NAME.json
  • --timezone, -z TZ - Override timezone for this command
  • --calendar, -c ID - Specify calendar ID or name (or use default from config)

Machine-readable errors go to stderr when --json or --jsonl is set. anymoment schema lists commands and exit codes. anymoment completion bash prints a shell snippet.

Exit codes: 0 ok, 2 usage, 3 auth, 4 not found, 5 conflict, 6 rate limited, 7 remote or sync error.

Library API Reference

Client Class

from anymoment import Client

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

Authentication

  • client.login(email, password) - Authenticate and get token
  • client.refresh_token() - Refresh current token
  • client.get_user_info() - Get current user information
  • client.resend_verification() - Send the verification email again
  • client.signup(email, password, ...) - Create an account
  • client.google - Google accounts, sync health, quarantine, and sync status
  • client.caldav - Experimental CalDAV. Remote auth failures do not refresh the session token.

Calendars

  • client.list_calendars(is_active=None, limit=None, offset=None) - List calendars
  • client.get_calendar(calendar_id) - Get calendar by ID
  • client.create_calendar(name, description=None, timezone="UTC", color=None) - Create calendar
  • client.update_calendar(calendar_id, name=None, description=None, timezone=None, color=None, is_active=None) - Update calendar
  • client.delete_calendar(calendar_id) - Delete calendar
  • client.share_calendar(calendar_id, user_id, role="viewer") - Share calendar with a user (set permissions)
  • client.update_calendar_share_role(calendar_id, user_id, role) - Update a shared user's role (owner, editor, viewer)
  • client.unshare_calendar(calendar_id, user_id) - Remove an AnyMoment share for a calendar
  • client.get_calendar_webhook_url(calendar_id) - Get webhook URL

Events

  • client.list_events(calendar_id=None, is_active=None, limit=None, offset=None, minimal=False) - List events
  • client.get_event(event_id) - Get event by ID
  • client.create_event_from_text(recurrence_text, name=None, description=None, timezone="UTC", calendar_id=None, model="high") - Create event from natural language
  • client.update_event(event_id, name=None, description=None) - Update event
  • client.delete_event(event_id) - Delete event
  • client.toggle_event(event_id) - Toggle event active status
  • client.get_event_instances(event_id, from_date=None, to_date=None, optimized=False) - Get event instances
  • client.get_next_event_instance(event_id) - Get next instance

Agenda & Search

  • client.get_agenda(start, end, calendar_ids=None, use_cache=True, include_webhooks=False) - Get events and their instances within a time window (agenda)
  • client.search_events(q, start=None, end=None, calendar_ids=None, is_active=None, limit=50, offset=0, include_instances=True) - Fuzzy search events by name (optional time window and filters)
  • client.link_event_to_calendar(calendar_id, event_id, display_order=None, color_override=None) - Add one event to a calendar
  • client.unlink_event_from_calendar(calendar_id, event_id) - Remove one event from a calendar (unlink only; event is not deleted)
  • client.batch_add_events_to_calendar(calendar_id, event_ids, display_order=None, color_override=None) - Add multiple events to a calendar in one request
  • client.batch_remove_events_from_calendar(calendar_id, event_ids) - Remove multiple events from a calendar (unlink only)

Examples

Natural Language Event Creation

# Simple weekly event
event = client.create_event_from_text(recurrence_text="Every Monday at 10 AM")

# Complex recurring pattern
event = client.create_event_from_text(
    recurrence_text="Weekdays from 9 to 5, except the 13th of every month",
    name="Work Hours",
    timezone="America/New_York"
)

# Multiple time windows
event = client.create_event_from_text(
    recurrence_text="Every Monday and Wednesday, from 9:00 to 12:00 and 13:00 to 17:00"
)

Working with Calendars

# Create and configure calendar
calendar = client.create_calendar(
    name="Personal",
    description="Personal events",
    timezone="America/New_York",
    color="#FF5733"
)

# Share with another user
client.share_calendar(
    calendar_id=calendar["id"],
    user_id="other-user-id",
    role="viewer"
)

# Get webhook URL for automation
webhook = client.get_calendar_webhook_url(calendar["id"])
print(f"Webhook URL: {webhook['webhook_url']}")

Getting Event Instances

# Get instances for a date range
instances = client.get_event_instances(
    event_id=event["id"],
    from_date="2026-01-01",
    to_date="2026-03-31"
)

# Get next instance
next_instance = client.get_next_event_instance(event["id"])
print(f"Next occurrence: {next_instance}")

Agenda & Search

# Get events and instances in a time window (agenda)
items = client.get_agenda(
    start="2026-01-01T00:00:00Z",
    end="2026-01-31T23:59:59Z",
    calendar_ids=[calendar["id"]],
    use_cache=True,
)
for item in items:
    print(item["event"]["name"], item["instances"])

# Fuzzy search events by name
results = client.search_events(
    q="team meeting",
    start="2026-01-01T00:00:00Z",
    end="2026-03-31T23:59:59Z",
    limit=20,
    include_instances=True,
)
for item in results:
    print(item["event"]["name"], item.get("score"), item.get("instances"))

Error Handling

The SDK raises specific exceptions for different error types:

from anymoment import (
    AuthenticationError,
    NotFoundError,
    ValidationError,
    ServerError,
)

try:
    calendar = client.get_calendar("invalid-id")
except NotFoundError:
    print("Calendar not found")
except AuthenticationError:
    print("Authentication failed - please login again")
except ValidationError as e:
    print(f"Validation error: {e.message}")
except ServerError as e:
    print(f"Server error: {e.message}")

Token Management

Tokens are automatically stored encrypted in ~/.anymoment/tokens.json using machine-specific encryption. The SDK handles:

  • Automatic token refresh on expiration
  • Multi-host token storage
  • Secure encryption using Fernet

Development

Running Tests

# Install development dependencies
pip install -e ".[cli]"
pip install pytest pytest-mock pytest-cov build twine

# Run tests
pytest

# Run with coverage
pytest --cov=anymoment --cov-report=html

Building Distribution

# Install build tools
pip install build twine

# Build distributions
python -m build

# Check distributions
twine check dist/*

License

MIT License - see LICENSE file for details.

Support

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Metadata

Release files for anymoment 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for anymoment 2.0.0
File Size Uploaded Provenance Actions
anymoment-2.0.0.tar.gz 56.1 kB With provenance Details for anymoment-2.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for anymoment 2.0.0
File Interpreter ABI Platform Actions
anymoment-2.0.0-py3-none-any.whl Python 3 none any Details for anymoment-2.0.0-py3-none-any.whl

Total release size: 96.7 kB

Release files / anymoment-2.0.0.tar.gz

Download URL anymoment-2.0.0.tar.gz
Size 56.1 kB
Tags Source
SHA-256 checksum
How to use checksums
a616cc7f6b5756606d98e2e52878c2423222bab10dcd8b3383a10b796544c3c2
BLAKE2b-256 checksum
How to use checksums
c377d90aa534a50471f12f301041e0456522665d9f3f45da0015a209e3063395
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / anymoment-2.0.0-py3-none-any.whl

Download URL anymoment-2.0.0-py3-none-any.whl
Size 40.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
456667acbf903f917f9c52b2fee7fd685a3ed813020a0eb0848f98326b750a63
BLAKE2b-256 checksum
How to use checksums
93f507bdae18c0bb5730b698f8c7637524abb5395936790e6290d864621aeda9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Security for anymoment 2.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for anymoment-2.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page