Skip to content

SDK v1.15.0

Latest

Choose a tag to compare

@github-actions github-actions released this 28 May 16:10
· 3 commits to main since this release

Highlights

Retry-safety overhaul for field --set and note create. Eliminates two retry hazards surfaced by a recent agent-driven intake incident:

  1. The four entity-field commands (entry/company/person/opportunity field --set) now pre-validate every value up front. A bad person id, unknown dropdown option, or malformed datetime aborts with exit 2 before any API write — instead of partial-committing the earlier --set values when a later one fails. Repeated --set of an unchanged value now also short-circuits both the DELETE and the POST, so agent retries no longer pollute the audit log with remove + add of the same value.
  2. note create emits a stderr warning when a content-identical note from the same author arrived within the last 5 minutes (creator scope resolved via cached /auth/whoami, rate-limit-exempt). The create itself still proceeds — informational only, with --skip-duplicate-check and --duplicate-window-seconds escape hatches.

Also fixes a latent bug where opportunity field --set on enriched fields was silently broken (V1 numeric id never resolved).

Breaking Changes

  • CLI: entry/company/person/opportunity field --set now performs upfront client-side validation. Failures the SDK can detect locally (invalid person/company id, unknown dropdown option, malformed datetime, etc.) raise a single aggregated CLIError (exit 2) before any API write. Previously, partial --set sequences would commit earlier values before a later one failed.
    • Migration: No code change needed for valid payloads. For agents that previously caught exit 2 and retried, the retry is now safe — no prior writes to undo. Server-side failures (HTTP 400 mid-sequence) may still leave partial state because Affinity has no transactions; see test_entry_field_partial_failure in tests/test_cli_entry_field.py for that scenario.

What's New

  • CLI: No-op short-circuit on field --set — when the new value already matches the existing value (dropdown id, person id, number, datetime, text), skip both the DELETE and the POST. Multi-value --set still writes whenever the new set differs from the existing set (subset is NOT a no-op — set semantics is REPLACE). Per-type comparator rules in affinity/cli/field_utils.py::value_equals_existing.
  • CLI: note create --skip-duplicate-check and --duplicate-window-seconds N flags. Default behavior emits a stderr warning when a content-identical note by the same author was created within the last N seconds (default 300). Useful safety net for AI agents that re-issue create after a parse failure on an earlier --json-less invocation.
  • CLI: Type-aware hint on _coerce_entity_id errors. Passing --set Owner "<full name>" now points the user at xaffinity person ls --json --query "<name>" to look up the numeric id, instead of bouncing the request to the server.
  • CLI: --output help text corrected — defaults to table regardless of pipe state. Pass --json explicitly when piping to a JSON parser.
  • SDK: New shared helpers in affinity.cli.field_utils: pre_validate_set_operations, value_equals_existing, execute_v1_set_phase, execute_v2_set_phase, execute_append_phase. The four entity-field commands now route through these helpers for consistent validate/no-op/write semantics.

Bug Fixes

  • opportunity field --set on enriched fields (e.g. --set "Source of Introduction" "...") now resolves to V1 numeric ids correctly. Previous code passed the enriched V2 literal directly to FieldValueCreate, breaking enriched-field writes on opportunities. Discovered during the migration to the shared set-phase helpers.
  • entry field --append no longer captures a stale existing-values snapshot between the set and append phases — the helper refresh handoff is explicit.

Plugin / MCP updates (shipped alongside)

  • xaffinity-cli plugin: 1.8.2 → 1.9.0 — two new pitfalls added to the xaffinity-cli-usage skill: (1) side-effecting commands must capture-then-parse (out=$(xaffinity ...)) rather than xaffinity ... | python3 -c "json.loads(...)", because pipeline exit codes drop the side-effect signal; (2) person/company field values require numeric IDs — the CLI now aborts cleanly on names with a hint at the lookup query.
  • xaffinity-mcp server: 1.22.1 → 1.22.2 — minimum CLI bumped to 1.15.0 (mcp/COMPATIBILITY) so the strict-by-default validation, no-op short-circuit, and duplicate-note warning are present for agents driving the MCP gateway. See mcp/CHANGELOG.md for details.

Quick Install

SDK only:

pip install affinity-sdk

SDK + CLI:

pipx install "affinity-sdk[cli]"

MCP Server for Claude Desktop (easiest - MCPB bundle):

  1. Install CLI: pipx install "affinity-sdk[cli]"
  2. (Optional) Pre-configure API key: xaffinity config setup-key
    • If skipped, Claude Desktop will prompt for your API key during install
  3. Install xaffinity MCP in Claude Desktop (download and double-click)

Other MCP clients (Cursor, Windsurf, VS Code, etc.) require manual configuration - see MCP docs.

Full documentation | MCP Server docs