Subjects

People, products, and brands being promoted.

13 actions. Each is callable by the agent as a tool, over HTTP via /api/invoke, and (usually) from a UI page.

subjects.list

GET

List subjects (people, products, brands, etc.) being promoted.

  • AI tool: subjects_list
  • API: GET /api/invoke/subjects.list

Input

Field Type Required Description
limit integer
offset integer
orderBy string
orderDir "asc" | "desc"
q string
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 500
    },
    "offset": {
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "orderBy": {
      "type": "string"
    },
    "orderDir": {
      "type": "string",
      "enum": [
        "asc",
        "desc"
      ]
    },
    "q": {
      "type": "string"
    }
  }
}

subjects.search

GET

Find subjects matching a query (name, handle, tags, or URL).

  • AI tool: subjects_search
  • API: GET /api/invoke/subjects.search

Input

Field Type Required Description
q string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "q": {
      "type": "string"
    }
  },
  "required": [
    "q"
  ]
}

subjects.get

GET

Get one subject by id.

  • AI tool: subjects_get
  • API: GET /api/invoke/subjects.get

Input

Field Type Required Description
id string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "id"
  ]
}

subjects.create

POST · mutating

Create a new subject (person/product/brand) to promote. Returns the new subject.

When the agent calls it: Call this when the user wants to promote a person, product, brand, project, event, or company that does not yet exist in the platform. type MUST be exactly one of: person, product, brand, project, event, company. Pick the closest fit (a place/home/property → project; an organization → company) — never pass a value outside this list. Only name and type are required. Use the returned subject id for follow-up calls like missions.create.

  • AI tool: subjects_create
  • API: POST /api/invoke/subjects.create

Input

Field Type Required Description
type "person" | "product" | "brand" | "project" | "event" | "company" yes
name string yes
handle string
headline string
description string
bio string
tags string[]
expertise string[]
links object[]
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "type": {
      "type": "string",
      "enum": [
        "person",
        "product",
        "brand",
        "project",
        "event",
        "company"
      ]
    },
    "name": {
      "type": "string"
    },
    "handle": {
      "type": "string"
    },
    "headline": {
      "type": "string"
    },
    "description": {
      "default": "",
      "type": "string"
    },
    "bio": {
      "type": "string"
    },
    "tags": {
      "default": [],
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "expertise": {
      "default": [],
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "links": {
      "default": [],
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "github",
              "website",
              "twitter",
              "linkedin",
              "youtube",
              "instagram",
              "tiktok",
              "threads",
              "bluesky",
              "blog",
              "paper",
              "talk",
              "podcast",
              "document",
              "pdf",
              "other"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "label": {
            "type": "string"
          },
          "verified": {
            "type": "boolean"
          },
          "followers": {
            "type": "number"
          }
        },
        "required": [
          "type",
          "url"
        ]
      }
    }
  },
  "required": [
    "type",
    "name"
  ]
}

subjects.update

PATCH · mutating

Update fields on a subject.

When the agent calls it: To add facts, pass patch.facts as an array of { fact: "", source?: "" }. Do not include ids or confidence — the server fills those in.

  • AI tool: subjects_update
  • API: PATCH /api/invoke/subjects.update

Input

Field Type Required Description
id string yes
patch object yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    },
    "patch": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "type": {
          "type": "string",
          "enum": [
            "person",
            "product",
            "brand",
            "project",
            "event",
            "company"
          ]
        },
        "name": {
          "type": "string"
        },
        "handle": {
          "type": "string"
        },
        "headline": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "bio": {
          "type": "string"
        },
        "tags": {
          "default": [],
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "expertise": {
          "default": [],
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "links": {
          "default": [],
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "enum": [
                  "github",
                  "website",
                  "twitter",
                  "linkedin",
                  "youtube",
                  "instagram",
                  "tiktok",
                  "threads",
                  "bluesky",
                  "blog",
                  "paper",
                  "talk",
                  "podcast",
                  "document",
                  "pdf",
                  "other"
                ]
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "label": {
                "type": "string"
              },
              "verified": {
                "type": "boolean"
              },
              "followers": {
                "type": "number"
              }
            },
            "required": [
              "type",
              "url"
            ]
          }
        },
        "voice": {
          "type": "object",
          "properties": {
            "tone": {
              "default": [],
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "doList": {
              "default": [],
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "dontList": {
              "default": [],
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "examplePosts": {
              "default": [],
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "forbiddenTopics": {
              "default": [],
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "catchphrases": {
              "default": [],
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        "audienceProfile": {
          "type": "object",
          "properties": {
            "primaryAudience": {
              "type": "string"
            },
            "demographics": {
              "type": "object",
              "propertyNames": {
                "type": "string"
              },
              "additionalProperties": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "number"
                  }
                ]
              }
            },
            "interests": {
              "default": [],
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        "facts": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "fact": {
                "type": "string"
              },
              "source": {
                "type": "string"
              },
              "confidence": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "category": {
                "type": "string"
              }
            },
            "required": [
              "fact"
            ]
          }
        },
        "createdAt": {},
        "updatedAt": {}
      }
    }
  },
  "required": [
    "id",
    "patch"
  ]
}

subjects.delete

DELETE · mutating

Soft-delete a subject. Sets deleted_at on the subject and cascade soft-deletes every mission tied to it. Reversible via subjects.restore. The row stays in the database so historical references (drafts, decisions, engagements) keep resolving.

When the agent calls it: Use this when the user wants to remove a subject from active lists. Confirms with the user first — cascades to all of the subject's missions.

  • AI tool: subjects_delete
  • API: DELETE /api/invoke/subjects.delete

Input

Field Type Required Description
id string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "id"
  ]
}

subjects.restore

POST · mutating

Restore a soft-deleted subject by clearing its deleted_at. Does NOT auto-restore cascaded missions — caller must restore those individually if desired.

  • AI tool: subjects_restore
  • API: POST /api/invoke/subjects.restore

Input

Field Type Required Description
id string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "id"
  ]
}

subjects.derive_voice

POST · mutating

Run the voice-profile derivation pass on a subject. When platform is set, derives a per-platform voice (different audience → different tone) under voice.byPlatform[platform]. When omitted, derives or returns the default profile. Per-platform presets cover twitter / patreon / devto / kickstarter / reddit / hackernews / producthunt / linkedin / instagram.

When the agent calls it: For a subject that posts on multiple platforms, derive voices ONE PLATFORM AT A TIME — call with platform="patreon", then "twitter", then "devto" etc. Each call adds to voice.byPlatform without disturbing the others.

  • AI tool: subjects_derive_voice
  • API: POST /api/invoke/subjects.derive_voice

Input

Field Type Required Description
id string yes
platform string
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    },
    "platform": {
      "type": "string"
    }
  },
  "required": [
    "id"
  ]
}

subjects.upsert_recipe

POST · mutating

Add or replace a publishing recipe on a subject. Recipes describe the default cadence for a category of content (dev-log, game-update, milestone, etc.) — each lists the channels to post on, in order, with delays. publish_to_channels reads these.

When the agent calls it: Recipe names are how the agent matches a topic to a cadence. Good names: "dev-log", "game-update", "milestone-celebration", "behind-the-scenes". Include matchKeywords to bias the classifier.

  • AI tool: subjects_upsert_recipe
  • API: POST /api/invoke/subjects.upsert_recipe

Input

Field Type Required Description
id string yes
recipe object yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    },
    "recipe": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1
        },
        "description": {
          "type": "string"
        },
        "matchKeywords": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "channels": {
          "minItems": 1,
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "order": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              },
              "platform": {
                "type": "string"
              },
              "personaSubjectId": {
                "type": "string",
                "minLength": 1
              },
              "contentMode": {
                "type": "string"
              },
              "delayMinutes": {
                "default": 0,
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              },
              "hashtags": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "audienceHint": {
                "type": "string"
              }
            },
            "required": [
              "order",
              "platform"
            ]
          }
        }
      },
      "required": [
        "name",
        "channels"
      ]
    }
  },
  "required": [
    "id",
    "recipe"
  ]
}

subjects.delete_recipe

DELETE · mutating

Remove a publishing recipe by name from a subject.

  • AI tool: subjects_delete_recipe
  • API: DELETE /api/invoke/subjects.delete_recipe

Input

Field Type Required Description
id string yes
name string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    },
    "name": {
      "type": "string"
    }
  },
  "required": [
    "id",
    "name"
  ]
}

subjects.list_recipes

GET

List publishing recipes attached to a subject.

  • AI tool: subjects_list_recipes
  • API: GET /api/invoke/subjects.list_recipes

Input

Field Type Required Description
id string yes
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "id"
  ]
}

subjects.resolve_recipe

POST

Pick one publishing recipe for a topic. When recipeName is provided, looks it up directly; otherwise runs the keyword classifier over the subject's recipes. Returns the recipe + classifier reason + confidence. Used by the platform-fanout workflow's first node to populate runningContext.recipe — then the foreach node iterates over recipe.channels.

  • AI tool: subjects_resolve_recipe
  • API: POST /api/invoke/subjects.resolve_recipe

Input

Field Type Required Description
subjectId string yes
topic string yes
recipeName string
useLlm boolean
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "subjectId": {
      "type": "string",
      "minLength": 1
    },
    "topic": {
      "type": "string"
    },
    "recipeName": {
      "type": "string"
    },
    "useLlm": {
      "type": "boolean"
    }
  },
  "required": [
    "subjectId",
    "topic"
  ]
}

subjects.find_similar

GET

Find subjects most semantically similar to a free-text query (pgvector kNN).

  • AI tool: subjects_find_similar
  • API: GET /api/invoke/subjects.find_similar

Input

Field Type Required Description
text string yes
limit integer
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "text": {
      "type": "string"
    },
    "limit": {
      "default": 10,
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    }
  },
  "required": [
    "text"
  ]
}