1. playbooks
temper
  • Temper documentation
  • cli
    • README
    • admin
    • auditor
    • auth
    • blob
    • check
    • cogmap
    • config
    • context
    • data-artifact
    • edge
    • graph
    • health
    • init
    • invitations
    • invocation
    • memory
    • profile
    • pull
    • query
    • resource
    • search
    • skill
    • slack
    • status
    • steward
    • team
    • trail
    • update
    • version
    • warmup
  • concepts
    • Auth Identity
    • Authoring Authorization
    • Contexts and Refs
    • Machine Tokens
    • Operational Memory
    • Release Verification
    • The SAML Reconcile Channel
    • Slack Identity and Revocation
    • Teams and Roles
    • Telemetry
    • Token Verification
    • The Trust Boundary
    • Query Cost and the Bounds That Shape It
    • Deleting a blob — custody, the ledger, and bytes
    • Erasure and the terms of use
    • Blob uploads
  • config
    • README
  • doors
    • Building against Temper
    • Running Temper
    • Using Temper
  • playbooks
    • Adopt operational memory
    • Authenticate
    • Bootstrap an Org
    • Bootstrap a Team's Self-Cognition
    • Build a cognitive map
    • Connect Claude Code
    • Connect Temper to Claude Desktop
    • Deliver L0 Kernel Content
    • Deploy a Steward Agent
    • Deploy the Web UI
    • Enterprise Install
    • Provision a Read-Only GitHub Connection
    • Ingest a corpus
    • Install Temper
    • Run a Team
    • Self-Host Temper
    • Self-host Temper with Okta
    • Self-host Temper with a SAML IdP
    • Send traces to an OTLP backend
    • Slack Mentions
    • Standing Up a Machine Credential
    • Commit structured data as an artifact
    • Compose Queries That Stay Fast
    • Offboard a Departure
    • Reblock a corpus
    • Rate-limit an instance at the edge
  • sdks
    • Integrating Ruby with temper-rb
  • Temper Cloud API
    • Reference
      • API Reference
        • Access
          • Request to join the gating team
          • Check your join request status
          • Withdraw your pending join request
          • Ask an admin to reconsider a revocation
          • Read public system settings
        • Slack Link
          • Disconnect any principal's Slack link
          • Disconnect all your own Slack links
        • Auditor
          • Claim a batch of auditor jobs
          • Survey audit coverage across findings
          • Complete a claimed auditor job
        • Graph
          • Slice a neighborhood within a cognitive map
          • Read a cognitive map's interior
          • Read a container's composition
          • Read goal-container territories and residuals
          • Read your teams and cognitive maps
          • Read the resources composing a region
          • Read what your work is built around
          • Traverse from where you are
        • Cognitive Maps
          • List cognitive maps you can see
          • Create a cognitive map and its telos charter
          • Get one cognitive map
          • Reconcile a cognitive map's contents
          • Read cognitive-map analytics
          • Grant access to a cognitive map
          • Revoke access to a cognitive map
          • Materialize a cognitive map's regions
          • Read formation drift since last materialize
          • Read per-region metrics for a map
          • Read a cognitive map's shape
          • Bind a team to a cognitive map
          • Unbind a team from a cognitive map
        • Contexts
          • List contexts you can see
          • Create a context
          • Resolve a context ref to its id
          • Get one context
          • Materialize a context's regions
          • Retire a context
          • Read per-region metrics for a context
          • Reassign a context to another owner
          • Read a context's shape
          • Rename a context
          • Read formation drift since a context's last materialize
          • Restore a retired context
          • Read a context's analytics
          • Share a context with a team
          • Stop sharing a context with a team
        • Events
          • Read a context's changes after a position
          • Read the event cursor for a context
          • Read a node or edge's event trail
        • Facets
          • Set a facet on a resource
          • Read the live facets of one edge
          • Set a facet on a relationship
          • Retract one facet of a relationship
          • Read the live facets of one resource
        • Health
          • Check service health
        • Ingest
          • Begin a segmented ingest
          • Update an in-progress ingest
          • List the blocks landed so far
          • Append a block to an in-progress ingest
          • Finalize a segmented ingest
        • Invitations
          • Accept a team invitation
          • Decline a team invitation
          • List invitations addressed to you
          • Count the invitations addressed to you
          • List a team's open invitations
          • Revoke a team invitation
          • Invite someone to a team
        • Invocations
          • List agent invocations
          • Open an invocation
          • Get one invocation
          • Close an invocation
        • Profile
          • Read your profile
          • Update your profile
          • List your linked identity providers
        • Query
          • Run a composition of situated acts
        • Relationships
          • Assert a relationship between resources
          • Fold a relationship
          • Change a relationship's type
          • Change a relationship's weight
        • Resources
          • Record a citation-audit verdict against a block's citation
          • List resources you can see
          • Create a resource
          • Get one resource
          • Soft-delete a resource
          • Update a resource
          • List a finding's citation-audit trail
          • Read one content block by address (the three-state resolution)
          • Record a citation-audit verdict
          • List a resource's relationships
          • Read a resource's reconstituted content
          • Read a resource's evidential standing
          • Grant access to a resource
          • Trace a resource's derivation lineage
          • Revoke access to a resource
          • Read a resource's block provenance
          • Attach provenance sources to a resource
          • Reassign a resource to another owner
          • List a resource's relationships, bounded, with the filtered total stated
        • Meta
          • Read a resource's frontmatter
          • Replace a resource's frontmatter
        • Search
          • Search resources by text or embedding
        • Steward
          • List steward candidates
          • Claim steward jobs for a worker
          • Survey steward drift across maps
          • Read a map's ingest delta
          • Advance a map's steward watermark
        • Teams
          • List teams you belong to
          • Create a team
          • Get one team
          • Delete a team
          • Update a team
          • Add a member to a team
          • Remove a member from a team
          • Attach a child team under this team
          • Change a member's role
          • Detach a child team from this team
          • Bulk reassign a team's resources
          • Set, change or clear a team's auto-join role
          • Change a team's slug
          • List the openings that confer on you
          • Forbid or allow public_within over a team's subtree
          • Move this team from one parent to another
          • Open a team's contexts to an ancestor's subtree
          • Restore a soft-deleted team
          • Close a team's opening to an ancestor's subtree
        • Data Artifacts
          • List artifacts for a resource, or counts with counts=true
          • Get a single artifact by ID under its owning resource
          • Commit one data artifact to a resource
          • Get a single artifact by ID — the flat read.
          • Read the artifacts one ask matches, whole
        • Data Artifact Shapes
          • List live shapes declared for a context home.
          • Declare a shape for a data-artifact family within a context home.
          • Get a single shape by ID, with what an ask may name
          • List live shapes declared for a cognitive-map home.
          • Declare a shape for a data-artifact family within a cognitive-map home.
        • Schema
          • List every document type this instance knows, with a schema summary for each.
          • Describe one document type: its JSON Schema, required fields, closed vocabularies, and a filled-in example of the managed tier.
          • Describe the recognized conventions of the open (caller-defined) metadata tier.
        • Blobs
          • List the blobs the caller can read (optionally scoped to one home)
          • Commit bytes as a blob — one multipart request at or under the D7 threshold
          • Begin a segmented upload — declare the home and media type, get the session id
          • Read a staged upload's progress — the resume read
          • Finalize a staged upload — assemble, hash, commit
          • Append one segment to a staged upload — raw bytes as the request body
          • Read a blob's bytes back, whole, streamed (D6)
          • Delete one blob — the ordinary delete act's ruled door
          • List the edges incident to a blob — "what relates to this blob" (D3)
          • Assert one relation between a blob and another anchor
        • Reblocking
          • Run one bounded, resumable re-blocking step
        • Admin
          • Reconcile auto-join team rosters
          • Revoke a profile's system-admin grant
          • Approve a principal
          • Deactivate a principal
          • Reactivate a principal
          • Revoke a principal's admission
          • List profiles in the operator directory
          • Show a profile's state card
          • Promote a profile to system admin
          • List pending join requests
          • Count pending join requests
          • Approve or reject a join request
          • List open reconsideration requests
          • Count open reconsideration requests
          • Close a reconsideration request
          • Read full system settings
          • Update system settings
          • Erase a principal
          • Survey a principal erasure
          • Scrub the history of resource blocks
          • Survey a block history scrub
          • Erase a resource
          • Survey a resource erasure
          • Scrub a resource field's history
          • List a resource's scrubbable fields
          • Survey a field scrub
          • List the erasure retention policy
          • Re-embed stale chunks
          • Set an erasure retention policy
          • Create a SAML group mapping
          • Rebind a machine client to a new client ID
          • Remove an erasure retention policy
          • Remove a SAML group mapping
        • Admin Ledger
          • Read the admin ledger
        • Connections
          • List connections
          • Provision a connection
          • Get a connection
          • Revoke a connection
          • Attach a connection credential
          • Grant a team read-reach on a connection
          • Revoke a team's read-reach on a connection
          • Set connection tool manifest
          • Set connection webhook events
        • Machine Clients
          • List machine clients
          • Register a machine client
          • Issue a machine credential
          • Get a machine client
          • Revoke a machine client
          • Rotate a machine client secret
        • Subscriptions
          • List subscriptions
          • Create a subscription
          • Get a subscription
          • Revoke a subscription
        • Me
          • When you last changed something in each context you can read
    • Schemas
      • AcceptInvitationResponse
      • ActInput
      • ActInvocation
      • ActName
      • ActQuantity
      • ActRefusal
      • ActorAuthority
      • AddMemberRequest
      • AdvanceWatermarkAck
      • AdminDirectoryEntry
      • AdvanceWatermarkRequest
      • AdminDirectoryListResponse
      • AgentAuthorship
      • AdminOpenJoinRequest
      • AdminLedgerEntry
      • AppendBlockPayload
      • AnchorAddressResolution
      • AdminOpenReviewRequest
      • AdminLedgerResponse
      • AdminProfileAuthLink
      • AtlasEdge
      • AnchorVerdict
      • AdminProfileCard
      • AtlasHome
      • AtlasEntry
      • AdminProfileInvitation
      • AdminProfileTeamMembership
      • AssertRelationshipRequest
      • AtlasNode
      • AtlasSubgraph
      • AdminProfilesListAnswer
      • AuditCitation
      • AuditorDispatchTickRequest
      • AuditorDispatchTickResponse
      • AuditorJobCompleteAck
      • BindTeamOutcome
      • BindTeamRequest
      • AnchorShape
      • BlockId
      • BlocksResponse
      • ArtifactCommitRequest
      • ArtifactAsk
      • BodyStorage
      • ArtifactAskPopulation
      • Bridge
      • ArtifactAskTrace
      • BulkReassignAck
      • AskOperator
      • ArtifactPredicate
      • BulkReassignRequest
      • ArtifactCommitResponse
      • BlobId
      • BlobDeleteAck
      • AskablePath
      • ChangeRoleRequest
      • BlobCommitResponse
      • BlobRelationAck
      • ArtifactCursor
      • CharterBlock
      • CharterDisposition
      • ArtifactView
      • BlobRelationAssertRequest
      • BlobRelationDirection
      • CitationAuditRequest
      • BlobRelationEdgeDirection
      • CitationAuditRow
      • BlobRelationRow
      • AttachCredentialResponse
      • AskOrder
      • ClaimedAuditJob
      • BlobSummary
      • AskRequest
      • AuditSweepRow
      • ClaimedJob
      • AskResponse
      • CloseInvocationRequest
      • BlobUploadBeginResponse
      • AutoJoinReconcileRow
      • CogmapAnalyticsRow
      • BlobUploadFinalizeRequest
      • AskedShape
      • CogmapDetail
      • BlobUploadBeginRequest
      • BlobUploadProgress
      • CogmapFoundationRow
      • BlobUploadSegmentInfo
      • BlobCoLinks
      • CogmapGrantBody
      • BlockChunkRef
      • BlockProvenanceRow
      • CogmapId
      • BlockFoldDisposition
      • CogmapRegionMetricsRow
      • CogmapRegionRow
      • CogmapRegulationRow
      • BlockRead
      • BlockCitationAuditRequest
      • AttachChildOutcome
      • CogmapRevokeBody
      • BlockSuccessor
      • CogmapRow
      • AttachOutcome
      • BlobStrikeView
      • CombineOp
      • CompositionTrace
      • CogmapStaleness
      • ConfidenceBand
      • Composition
      • ContextId
      • ContextOwnerRef
      • ContextPanorama
      • CorrelationId
      • CreateCogmapOutcome
      • BlockHistoryScrubExecuteResponse
      • CreateCogmapRequest
      • BlockHistoryScrubPlan
      • BlockHistoryScrubRequestBody
      • ContextRowWithCounts
      • CreateRequestBody
      • BlockHistoryScrubSurvey
      • CreateReviewBody
      • DeleteResponse
      • DeviceOverrides
      • DispatchTickRequest
      • DataArtifactId
      • BlockScrubCount
      • DispatchTickResponse
      • Disposition
      • DriftSweepRow
      • DiscouragedOpenMetaKey
      • EdgeFacetsResponse
      • CloseReviewBody
      • EdgeId
      • EdgeKind
      • DocTypeDescription
      • DocTypeSummary
      • ElementKind
      • EmbedDispatchSummary
      • ErrorBody
      • EntryBounds
      • BoundKind
      • ErrorDetails
      • EventTrail
      • EnforcementMode
      • ExactHit
      • ByteBlock
      • FacetAck
      • FinalizePayload
      • FoldRelationshipRequest
      • CombineNode
      • GrantOutcome
      • ConnectionCredential
      • ConnectionSubscription
      • GroupKeyMeta
      • HealthResponse
      • HomeCogmap
      • HomeContext
      • IdKind
      • EdgeFacetSetRequest
      • IdProvenance
      • ContextResolution
      • ContextCreateRequest
      • FacetSetRequest
      • IdpRevocation
      • IngestCreateResponse
      • IngestDelta
      • ElementEvent
      • DemoteAdminRequest
      • InheritedReadGrant
      • InheritedShare
      • EmbeddingStatus
      • InputSource
      • CredentialVerification
      • InvitationStatus
      • InviteeInvitation
      • ContextActivity
      • InvocationAck
      • ContextChange
      • ContentResponse
      • ContextChangeSubject
      • InvocationCloseAck
      • ContextChangesResponse
      • InvocationId
      • GraphEdgeRow
      • InvocationSummary
      • DeriverFingerprint
      • JoinRequest
      • Intention
      • JoinRequestStatus
      • FacetRetractAck
      • LensId
      • LineageNode
      • ContextRow
      • CreateInvitationRequest
      • ManagedMeta
      • MatchLocation
      • ErasureExecuteRequest
      • CreateSubscriptionRequest
      • EdgeFacetRow
      • MaterializeRequest
      • KindOwnerInput
      • MergePolicy
      • ErasureSurveyRequest
      • EdgeFilter
      • NarrowedBy
      • ErasureTargetOutcome
      • NodeHome
      • CreateSamlGroupMappingOutcome
      • OpenInvocationRequest
      • CreateSamlGroupMappingRequest
      • OrdOp
      • OrphanNode
      • EventId
      • MaterializeAck
      • PlanRefusalDetails
      • Entitlements
      • MaterializeDelta
      • Polarity
      • Profile
      • ProfileAuthLink
      • ProfileId
      • ErasureExecuteResponse
      • ProfileUpdateRequest
      • ErasureSurveyResponse
      • OpenMetaConvention
      • ProvenanceSource
      • PublicSystemSettings
      • QuantityScale
      • EstateCounts
      • QueryResponse
      • EstateDisposition
      • ReassignAck
      • EstateErasureKind
      • EstateResourceErasure
      • ReassignContextRequest
      • EstateResourcePlan
      • ReassignResourceRequest
      • GrantConnectionReachRequest
      • FacetPredicate
      • ReconcileCogmapRequest
      • ReconcileEdge
      • GrantSpec
      • ReconcileEdgeTombstone
      • ProfileWithEntitlements
      • ReconcileEntry
      • ReconcileOutcome
      • FieldScrubClearingEvent
      • ExactArm
      • ReconcileTelos
      • FingerprintMatch
      • FieldScrubExecuteResponse
      • ReconcileTelosBlock
      • FieldScrubFamilies
      • ReconcileTombstone
      • FieldScrubFamiliesRequest
      • Refusal
      • FieldScrubHeldPaths
      • RegionHit
      • RegionDisclosure
      • FieldScrubPlan
      • RegionId
      • FieldScrubRefusalReason
      • RelationshipAck
      • FieldScrubRequestBody
      • ErrorDetail
      • RemoveMemberOutcome
      • FieldScrubFamily
      • RenameContextOutcome
      • RenameContextRequest
      • ResidualBucket
      • ResidualContext
      • ResidualGroups
      • FieldScrubSurvey
      • EventCursorResponse
      • ResidualOwnedReach
      • IngestEnded
      • ResourceAnnotateRequest
      • IngestState
      • ResourceCreateRequest
      • JoinRequestWithProfile
      • ResourceFacetRow
      • ResourceFacets
      • ResourceFacetsResponse
      • Extent
      • ResourceGrantBody
      • ResourceId
      • IssueMachineRequest
      • InvitationTokenRequest
      • ResourceLineage
      • ResourceListResponse
      • FailedExpectation
      • ResourceRevokeBody
      • IdSet
      • LedgerRef
      • ReblockCandidate
      • LedgerRefKind
      • ReturnSpec
      • LedgerRefRel
      • IngestPayload
      • RetypeRelationshipRequest
      • ReblockReceipt
      • LedgerRefTarget
      • RevokeOutcome
      • ReblockRequest
      • ReweightRelationshipRequest
      • ReblockScope
      • OtherAuthorEdge
      • ReblockSummary
      • OtherAuthorEdgeProperty
      • RelationshipTarget
      • SearchReason
      • SearchResponse
      • SearchResultRow
      • SearchScope
      • InvocationActRow
      • SearchScopeInfo
      • SegmentedBegin
      • SegmentedBeginResponse
      • InvocationView
      • ShareContextOutcome
      • RestoreContextOutcome
      • PromoteAdminRequest
      • ShareContextRequest
      • RetireContextOutcome
      • PropertyId
      • SlackDisconnectRequest
      • IssuedMachineCredential
      • SlackDisconnectResponse
      • SlackDisconnectedPrincipal
      • SliceRequest
      • SortOrder
      • InheritedPublicWithin
      • StageDisposition
      • StageInput
      • QueueCount
      • StageInputTrace
      • JsonType
      • StageName
      • ShapeId
      • StageNode
      • OutcomeDeclaration
      • StageOutput
      • StageRelation
      • ResourceConnections
      • RebindMachineRequest
      • ShapeEmptiness
      • PendingInvitationCounts
      • Standing
      • Subscription
      • SubscriptionOverride
      • SystemAccessDetails
      • ReconcileAutoJoinOutcome
      • ProvisionConnectionRequest
      • ProvisionMachineRequest
      • PropertyOp
      • TeamMemberDetail
      • PropertyPredicate
      • TeamMemberRow
      • TeamMemberSource
      • TeamRole
      • MachineClient
      • TeamUpdateRequest
      • RedactedEventFields
      • Territory
      • ReembedRequest
      • TerritoryKind
      • ReembedSummary
      • TerritoryOverview
      • UnbindTeamOutcome
      • UnshareContextOutcome
      • VaultConfig
      • PlanRefusal
      • Scoring
      • WideHit
      • ReblockOutcome
      • OversizedArtifact
      • MetaExpect
      • MetaUpdatePayload
      • PathFacts
      • ResourceErasureExecuteRequest
      • ResourceErasureRefusalReason
      • ResourceErasureSurveyRequest
      • RemoteConnection
      • ViaEntry
      • PreconditionFailure
      • PreconditionTier
      • PublicWithinAudience
      • PublicWithinInRef
      • PublicWithinOpenKind
      • PublicWithinEffects
      • PublicWithinOutcome
      • PublicWithinPolicyOutcome
      • ReviewRequestBody
      • PublicWithinPolicyRequest
      • ReviewRequestWithProfile
      • PublicWithinRef
      • ResourceErasureExecuteResponse
      • PublicWithinRowRef
      • RevokePrincipalBody
      • PublicWithinReach
      • ResourceErasurePlan
      • ResourceErasureSurvey
      • RefusalTeaching
      • Reach
      • ReassignContextOutcome
      • ResourceFilter
      • ReachVia
      • RotateSecretRequest
      • ResourceHit
      • SearchParams
      • RenameTeamSlugOutcome
      • RenameTeamSlugRequest
      • SetToolManifestRequest
      • SetWebhookEventsRequest
      • ReparentRequest
      • RetentionCategory
      • RetentionPolicies
      • RetentionPolicy
      • RefusalReason
      • RetentionPolicySet
      • ScrubFieldKind
      • ScrubbedField
      • RemoveSamlGroupMappingOutcome
      • ReparentOutcome
      • ResourceSortField
      • UpdateSettingsRequest
      • SubscriptionSelector
      • TeamSpec
      • SlackRevocationTally
      • ResourceSection
      • ShapeHome
      • ResourceView
      • ShapeSuccessor
      • RestoreTeamOutcome
      • ResourceUpdateRequest
      • ShapeDeclareRequest
      • ShapeView
      • SetAutoJoinRequest
      • SamlGroupMapping
      • StageTrace
      • ScoreKind
      • TeachingElision
      • SegmentInfo
      • SetAutoJoinOutcome
      • TeamInvitation
      • StandingShape
      • WideArm
      • WideDraw
      • TeamChildRef
      • TeamCreateRequest
      • Vocabulary
      • TeamRef
      • TeamDetail
      • StageResult
      • SystemSettings
      • TeamRow
  • Temper Cloud API
    • Reference
      • API Reference
        • Access
          • Request to join the gating team
          • Check your join request status
          • Withdraw your pending join request
          • Ask an admin to reconsider a revocation
          • Read public system settings
        • Slack Link
          • Disconnect any principal's Slack link
          • Disconnect all your own Slack links
        • Auditor
          • Claim a batch of auditor jobs
          • Survey audit coverage across findings
          • Complete a claimed auditor job
        • Blobs
          • List the blobs the caller can read (optionally scoped to one home)
          • Commit bytes as a blob — one multipart request at or under the D7 threshold
          • Begin a segmented upload — declare the home and media type, get the session id
          • Read a staged upload's progress — the resume read
          • Finalize a staged upload — assemble, hash, commit
          • Append one segment to a staged upload — raw bytes as the request body
          • Read a blob's bytes back, whole, streamed (D6)
          • Delete one blob — the ordinary delete act's ruled door
          • List the edges incident to a blob — "what relates to this blob" (D3)
          • Assert one relation between a blob and another anchor
        • Graph
          • Slice a neighborhood within a cognitive map
          • Read a cognitive map's interior
          • Read a container's composition
          • Read goal-container territories and residuals
          • Read what your work is built around
          • Read your teams and cognitive maps
          • Read the resources composing a region
          • Traverse from where you are
        • Cognitive Maps
          • List cognitive maps you can see
          • Create a cognitive map and its telos charter
          • Get one cognitive map
          • Reconcile a cognitive map's contents
          • Read cognitive-map analytics
          • Grant access to a cognitive map
          • Revoke access to a cognitive map
          • Materialize a cognitive map's regions
          • Read formation drift since last materialize
          • Read per-region metrics for a map
          • Read a cognitive map's shape
          • Bind a team to a cognitive map
          • Unbind a team from a cognitive map
        • Contexts
          • List contexts you can see
          • Create a context
          • Get one context
          • Retire a context
          • Read a context's analytics
          • Materialize a context's regions
          • Read formation drift since a context's last materialize
          • Reassign a context to another owner
          • Read per-region metrics for a context
          • Rename a context
          • Restore a retired context
          • Read a context's shape
          • Share a context with a team
          • Stop sharing a context with a team
        • Data Artifact Shapes
          • List live shapes declared for a context home.
          • Declare a shape for a data-artifact family within a context home.
          • Get a single shape by ID.
        • Events
          • Read the event cursor for a context
          • Read a node or edge's event trail
        • Facets
          • Set a facet on a resource
          • Read the live facets of one edge
          • Set a facet on a relationship
          • Retract one facet of a relationship
          • Read the live facets of one resource
        • Health
          • Check service health
        • Ingest
          • Begin a segmented ingest
          • Update an in-progress ingest
          • List the blocks landed so far
          • Append a block to an in-progress ingest
          • Finalize a segmented ingest
        • Invitations
          • Accept a team invitation
          • Decline a team invitation
          • List invitations addressed to you
          • Count the invitations addressed to you
          • List a team's open invitations
          • Revoke a team invitation
          • Invite someone to a team
        • Invocations
          • List agent invocations
          • Open an invocation
          • Get one invocation
          • Close an invocation
        • Profile
          • Read your profile
          • Update your profile
          • List your linked identity providers
        • Query
          • Run a composition of situated acts
        • Relationships
          • Assert a relationship between resources
          • Fold a relationship
          • Change a relationship's type
          • Change a relationship's weight
        • Resources
          • List resources you can see
          • Create a resource
          • Get one resource
          • Soft-delete a resource
          • Update a resource
          • Read one content block by address (the three-state resolution)
          • List a finding's citation-audit trail
          • Record a citation-audit verdict
          • Read a resource's reconstituted content
          • List a resource's relationships
          • Read a resource's evidential standing
          • Grant access to a resource
          • Revoke access to a resource
          • Trace a resource's derivation lineage
          • Read a resource's block provenance
          • Attach provenance sources to a resource
          • Reassign a resource to another owner
        • Reblocking
          • Run one bounded, resumable re-blocking step
        • Data Artifacts
          • List artifacts for a resource, or counts with counts=true
          • Commit one data artifact to a resource
          • Get a single artifact by ID under its owning resource
        • Meta
          • Read a resource's frontmatter
          • Replace a resource's frontmatter
        • Schema
          • List every document type this instance knows, with a schema summary for each.
          • Describe one document type: its JSON Schema, required fields, closed vocabularies, and a filled-in example of the managed tier.
          • Describe the recognized conventions of the open (caller-defined) metadata tier.
        • Search
          • Search resources by text or embedding
        • Steward
          • List steward candidates
          • Claim steward jobs for a worker
          • Survey steward drift across maps
          • Read a map's ingest delta
          • Advance a map's steward watermark
        • Teams
          • List teams you belong to
          • Create a team
          • Get one team
          • Delete a team
          • Update a team
          • Add a member to a team
          • Remove a member from a team
          • Change a member's role
          • Bulk reassign a team's resources
    • Schemas
      • AcceptInvitationResponse
      • ActInput
      • ActInvocation
      • ActName
      • ActQuantity
      • ActRefusal
      • ActorAuthority
      • AddMemberRequest
      • AdvanceWatermarkAck
      • AdvanceWatermarkRequest
      • AgentAuthorship
      • AnchorAddressResolution
      • AnchorShape
      • AnchorVerdict
      • AppendBlockPayload
      • ArtifactCommitRequest
      • ArtifactCommitResponse
      • ArtifactView
      • AssertRelationshipRequest
      • AtlasEdge
      • AtlasEntry
      • AtlasHome
      • AtlasNode
      • AtlasSubgraph
      • AuditCitation
      • AuditSweepRow
      • AuditorDispatchTickRequest
      • AuditorDispatchTickResponse
      • AuditorJobCompleteAck
      • BindTeamOutcome
      • BindTeamRequest
      • BlobCommitResponse
      • BlobDeleteAck
      • BlobId
      • BlobRelationAck
      • BlobRelationAssertRequest
      • BlobRelationDirection
      • BlobRelationEdgeDirection
      • BlobRelationRow
      • BlobSummary
      • BlobUploadBeginRequest
      • BlobUploadBeginResponse
      • BlobUploadFinalizeRequest
      • BlobUploadProgress
      • BlobUploadSegmentInfo
      • BlockChunkRef
      • BlockFoldDisposition
      • BlockId
      • BlockProvenanceRow
      • BlockRead
      • BlockSuccessor
      • BlocksResponse
      • BodyStorage
      • Bridge
      • BulkReassignAck
      • BulkReassignRequest
      • ChangeRoleRequest
      • CharterBlock
      • CharterDisposition
      • CitationAuditRequest
      • CitationAuditRow
      • ClaimedAuditJob
      • ClaimedJob
      • CloseInvocationRequest
      • CogmapAnalyticsRow
      • CogmapDetail
      • CogmapFoundationRow
      • CogmapGrantBody
      • CogmapId
      • CogmapRegionMetricsRow
      • CogmapRegionRow
      • CogmapRegulationRow
      • CogmapRevokeBody
      • CogmapRow
      • CogmapStaleness
      • CombineNode
      • CombineOp
      • Composition
      • CompositionTrace
      • ConfidenceBand
      • ContentResponse
      • ContextCreateRequest
      • ContextId
      • ContextOwnerRef
      • ContextPanorama
      • ContextRow
      • ContextRowWithCounts
      • CorrelationId
      • CreateCogmapOutcome
      • CreateCogmapRequest
      • CreateInvitationRequest
      • CreateRequestBody
      • CreateReviewBody
      • DataArtifactId
      • DeleteResponse
      • DeviceOverrides
      • DiscouragedOpenMetaKey
      • DispatchTickRequest
      • DispatchTickResponse
      • Disposition
      • DocTypeDescription
      • DocTypeSummary
      • DriftSweepRow
      • EdgeFacetRow
      • EdgeFacetSetRequest
      • EdgeFacetsResponse
      • EdgeFilter
      • EdgeId
      • EdgeKind
      • ElementEvent
      • ElementKind
      • EmbedDispatchSummary
      • EnforcementMode
      • Entitlements
      • EntryBounds
      • ErrorBody
      • ErrorDetail
      • ErrorDetails
      • EventCursorResponse
      • EventTrail
      • ExactArm
      • ExactHit
      • Extent
      • FacetAck
      • FacetPredicate
      • FacetRetractAck
      • FacetSetRequest
      • FinalizePayload
      • FoldRelationshipRequest
      • GrantOutcome
      • GraphEdgeRow
      • GroupKeyMeta
      • HealthResponse
      • HomeCogmap
      • HomeContext
      • IdKind
      • IdProvenance
      • IdSet
      • IdpRevocation
      • IngestCreateResponse
      • IngestDelta
      • IngestPayload
      • IngestState
      • InheritedReadGrant
      • InheritedShare
      • InputSource
      • Intention
      • InvitationStatus
      • InvitationTokenRequest
      • InviteeInvitation
      • InvocationAck
      • InvocationActRow
      • InvocationCloseAck
      • InvocationId
      • InvocationSummary
      • InvocationView
      • JoinRequest
      • JoinRequestStatus
      • KindOwnerInput
      • LensId
      • LineageNode
      • ManagedMeta
      • MatchLocation
      • MaterializeAck
      • MaterializeDelta
      • MaterializeRequest
      • MergePolicy
      • MetaUpdatePayload
      • NarrowedBy
      • NodeHome
      • OpenInvocationRequest
      • OpenMetaConvention
      • OrdOp
      • OrphanNode
      • OutcomeDeclaration
      • PendingInvitationCounts
      • PlanRefusal
      • PlanRefusalDetails
      • Polarity
      • Profile
      • ProfileAuthLink
      • ProfileId
      • ProfileUpdateRequest
      • ProfileWithEntitlements
      • PropertyOp
      • PropertyPredicate
      • ProvenanceSource
      • PublicSystemSettings
      • QuantityScale
      • QueryResponse
      • ReassignAck
      • ReassignContextOutcome
      • ReassignContextRequest
      • ReassignResourceRequest
      • ReblockCandidate
      • ReblockOutcome
      • ReblockReceipt
      • ReblockRequest
      • ReblockScope
      • ReblockSummary
      • ReconcileCogmapRequest
      • ReconcileEdge
      • ReconcileEdgeTombstone
      • ReconcileEntry
      • ReconcileOutcome
      • ReconcileTelos
      • ReconcileTelosBlock
      • ReconcileTombstone
      • Refusal
      • RefusalReason
      • RegionDisclosure
      • RegionHit
      • RegionId
      • RelationshipAck
      • RelationshipTarget
      • RemoveMemberOutcome
      • RenameContextOutcome
      • RenameContextRequest
      • ResidualBucket
      • ResidualContext
      • ResidualGroups
      • ResidualOwnedReach
      • ResourceAnnotateRequest
      • ResourceCreateRequest
      • ResourceFacetRow
      • ResourceFacets
      • ResourceFacetsResponse
      • ResourceFilter
      • ResourceGrantBody
      • ResourceHit
      • ResourceId
      • ResourceLineage
      • ResourceListResponse
      • ResourceRevokeBody
      • ResourceSection
      • ResourceSortField
      • ResourceUpdateRequest
      • ResourceView
      • RestoreContextOutcome
      • RetireContextOutcome
      • ReturnSpec
      • RetypeRelationshipRequest
      • RevokeOutcome
      • ReweightRelationshipRequest
      • ScoreKind
      • Scoring
      • SearchParams
      • SearchReason
      • SearchResponse
      • SearchResultRow
      • SearchScope
      • SearchScopeInfo
      • SegmentInfo
      • SegmentedBegin
      • SegmentedBeginResponse
      • ShapeDeclareRequest
      • ShapeEmptiness
      • ShapeId
      • ShapeView
      • ShareContextOutcome
      • ShareContextRequest
      • SlackDisconnectRequest
      • SlackDisconnectResponse
      • SlackDisconnectedPrincipal
      • SliceRequest
      • SortOrder
      • StageDisposition
      • StageInput
      • StageInputTrace
      • StageName
      • StageNode
      • StageOutput
      • StageRelation
      • StageResult
      • StageTrace
      • Standing
      • StandingShape
      • Subscription
      • SubscriptionOverride
      • SystemAccessDetails
      • TeamCreateRequest
      • TeamDetail
      • TeamInvitation
      • TeamMemberDetail
      • TeamMemberRow
      • TeamMemberSource
      • TeamRole
      • TeamRow
      • TeamUpdateRequest
      • Territory
      • TerritoryKind
      • TerritoryOverview
      • UnbindTeamOutcome
      • UnshareContextOutcome
      • VaultConfig
      • ViaEntry
      • WideArm
      • WideHit
  • Temper Cloud API
    • Reference
      • API Reference
        • Admin
          • Reconcile auto-join team rosters
          • Revoke a profile's system-admin grant
          • Approve a principal
          • Deactivate a principal
          • Reactivate a principal
          • Revoke a principal's admission
          • List profiles in the operator directory
          • Show a profile's state card
          • Promote a profile to system admin
          • List pending join requests
          • Count pending join requests
          • Approve or reject a join request
          • List open reconsideration requests
          • Count open reconsideration requests
          • Close a reconsideration request
          • Read full system settings
          • Update system settings
          • Erase a principal
          • Survey a principal erasure
          • Scrub the history of resource blocks
          • Survey a block history scrub
          • Erase a resource
          • Survey a resource erasure
          • Re-embed stale chunks
          • Rebind a machine client to a new client ID
        • Access
          • Request to join the gating team
          • Check your join request status
          • Withdraw your pending join request
          • Ask an admin to reconsider a revocation
          • Read public system settings
        • Admin Ledger
          • Read the admin ledger
        • Slack Link
          • Disconnect any principal's Slack link
          • Disconnect all your own Slack links
        • Auditor
          • Claim a batch of auditor jobs
          • Survey audit coverage across findings
          • Complete a claimed auditor job
        • Blobs
          • List the blobs the caller can read (optionally scoped to one home)
          • Commit bytes as a blob — one multipart request at or under the D7 threshold
          • Begin a segmented upload — declare the home and media type, get the session id
          • Read a staged upload's progress — the resume read
          • Finalize a staged upload — assemble, hash, commit
          • Append one segment to a staged upload — raw bytes as the request body
          • Read a blob's bytes back, whole, streamed (D6)
          • Delete one blob — the ordinary delete act's ruled door
          • List the edges incident to a blob — "what relates to this blob" (D3)
          • Assert one relation between a blob and another anchor
        • Resources
          • Record a citation-audit verdict against a block's citation
          • List resources you can see
          • Create a resource
          • Get one resource
          • Soft-delete a resource
          • Update a resource
          • Read one content block by address (the three-state resolution)
          • List a finding's citation-audit trail
          • Record a citation-audit verdict
          • List a resource's relationships, bounded, with the filtered total stated
          • Read a resource's reconstituted content
          • List a resource's relationships
          • Read a resource's evidential standing
          • Grant access to a resource
          • Revoke access to a resource
          • Trace a resource's derivation lineage
          • Read a resource's block provenance
          • Attach provenance sources to a resource
          • Reassign a resource to another owner
        • Graph
          • Slice a neighborhood within a cognitive map
          • Read a cognitive map's interior
          • Read a container's composition
          • Read goal-container territories and residuals
          • Read what your work is built around
          • Read your teams and cognitive maps
          • Read the resources composing a region
          • Traverse from where you are
        • Cognitive Maps
          • List cognitive maps you can see
          • Create a cognitive map and its telos charter
          • Get one cognitive map
          • Reconcile a cognitive map's contents
          • Read cognitive-map analytics
          • Grant access to a cognitive map
          • Revoke access to a cognitive map
          • Materialize a cognitive map's regions
          • Read formation drift since last materialize
          • Read per-region metrics for a map
          • Read a cognitive map's shape
          • Bind a team to a cognitive map
          • Unbind a team from a cognitive map
        • Data Artifact Shapes
          • List live shapes declared for a cognitive-map home.
          • Declare a shape for a data-artifact family within a cognitive-map home.
          • List live shapes declared for a context home.
          • Declare a shape for a data-artifact family within a context home.
          • Get a single shape by ID.
        • Connections
          • List connections
          • Provision a connection
          • Get a connection
          • Revoke a connection
          • Attach a connection credential
          • Grant a team read-reach on a connection
          • Revoke a team's read-reach on a connection
          • Set connection tool manifest
          • Set connection webhook events
        • Contexts
          • List contexts you can see
          • Create a context
          • Resolve a context ref to its id
          • Get one context
          • Retire a context
          • Read a context's analytics
          • Materialize a context's regions
          • Read formation drift since a context's last materialize
          • Reassign a context to another owner
          • Read per-region metrics for a context
          • Rename a context
          • Restore a retired context
          • Read a context's shape
          • Share a context with a team
          • Stop sharing a context with a team
        • Data Artifacts
          • Get a single artifact by ID — the flat read.
          • List artifacts for a resource, or counts with counts=true
          • Commit one data artifact to a resource
          • Get a single artifact by ID under its owning resource
        • Events
          • Read the event cursor for a context
          • Read a node or edge's event trail
        • Facets
          • Set a facet on a resource
          • Read the live facets of one edge
          • Set a facet on a relationship
          • Retract one facet of a relationship
          • Read the live facets of one resource
        • Health
          • Check service health
        • Ingest
          • Begin a segmented ingest
          • Update an in-progress ingest
          • List the blocks landed so far
          • Append a block to an in-progress ingest
          • Finalize a segmented ingest
        • Invitations
          • Accept a team invitation
          • Decline a team invitation
          • List invitations addressed to you
          • Count the invitations addressed to you
          • List a team's open invitations
          • Revoke a team invitation
          • Invite someone to a team
        • Invocations
          • List agent invocations
          • Open an invocation
          • Get one invocation
          • Close an invocation
        • Machine Clients
          • List machine clients
          • Register a machine client
          • Issue a machine credential
          • Get a machine client
          • Revoke a machine client
          • Rotate a machine client secret
        • Profile
          • Read your profile
          • Update your profile
          • List your linked identity providers
        • Query
          • Run a composition of situated acts
        • Relationships
          • Assert a relationship between resources
          • Fold a relationship
          • Change a relationship's type
          • Change a relationship's weight
        • Reblocking
          • Run one bounded, resumable re-blocking step
        • Meta
          • Read a resource's frontmatter
          • Replace a resource's frontmatter
        • Schema
          • List every document type this instance knows, with a schema summary for each.
          • Describe one document type: its JSON Schema, required fields, closed vocabularies, and a filled-in example of the managed tier.
          • Describe the recognized conventions of the open (caller-defined) metadata tier.
        • Search
          • Search resources by text or embedding
        • Steward
          • List steward candidates
          • Claim steward jobs for a worker
          • Survey steward drift across maps
          • Read a map's ingest delta
          • Advance a map's steward watermark
        • Subscriptions
          • List subscriptions
          • Create a subscription
          • Get a subscription
          • Revoke a subscription
        • Teams
          • List teams you belong to
          • Create a team
          • Get one team
          • Delete a team
          • Update a team
          • Add a member to a team
          • Remove a member from a team
          • Change a member's role
          • Bulk reassign a team's resources
    • Schemas
      • AcceptInvitationResponse
      • ActInput
      • ActInvocation
      • ActName
      • ActQuantity
      • ActRefusal
      • ActorAuthority
      • AddMemberRequest
      • AdminDirectoryEntry
      • AdminDirectoryListResponse
      • AdminLedgerEntry
      • AdminLedgerResponse
      • AdminOpenJoinRequest
      • AdminOpenReviewRequest
      • AdminProfileAuthLink
      • AdminProfileCard
      • AdminProfileInvitation
      • AdminProfileTeamMembership
      • AdminProfilesListAnswer
      • AdvanceWatermarkAck
      • AdvanceWatermarkRequest
      • AgentAuthorship
      • AnchorAddressResolution
      • AnchorShape
      • AnchorVerdict
      • AppendBlockPayload
      • ArtifactCommitRequest
      • ArtifactCommitResponse
      • ArtifactView
      • AssertRelationshipRequest
      • AtlasEdge
      • AtlasEntry
      • AtlasHome
      • AtlasNode
      • AtlasSubgraph
      • AttachCredentialResponse
      • AuditCitation
      • AuditSweepRow
      • AuditorDispatchTickRequest
      • AuditorDispatchTickResponse
      • AuditorJobCompleteAck
      • AutoJoinReconcileRow
      • BindTeamOutcome
      • BindTeamRequest
      • BlobCoLinks
      • BlobCommitResponse
      • BlobDeleteAck
      • BlobId
      • BlobRelationAck
      • BlobRelationAssertRequest
      • BlobRelationDirection
      • BlobRelationEdgeDirection
      • BlobRelationRow
      • BlobStrikeView
      • BlobSummary
      • BlobUploadBeginRequest
      • BlobUploadBeginResponse
      • BlobUploadFinalizeRequest
      • BlobUploadProgress
      • BlobUploadSegmentInfo
      • BlockChunkRef
      • BlockCitationAuditRequest
      • BlockFoldDisposition
      • BlockHistoryScrubExecuteResponse
      • BlockHistoryScrubPlan
      • BlockHistoryScrubRequestBody
      • BlockHistoryScrubSurvey
      • BlockId
      • BlockProvenanceRow
      • BlockRead
      • BlockScrubCount
      • BlockSuccessor
      • BlocksResponse
      • BodyStorage
      • Bridge
      • BulkReassignAck
      • BulkReassignRequest
      • ChangeRoleRequest
      • CharterBlock
      • CharterDisposition
      • CitationAuditRequest
      • CitationAuditRow
      • ClaimedAuditJob
      • ClaimedJob
      • CloseInvocationRequest
      • CloseReviewBody
      • CogmapAnalyticsRow
      • CogmapDetail
      • CogmapFoundationRow
      • CogmapGrantBody
      • CogmapId
      • CogmapRegionMetricsRow
      • CogmapRegionRow
      • CogmapRegulationRow
      • CogmapRevokeBody
      • CogmapRow
      • CogmapStaleness
      • CombineNode
      • CombineOp
      • Composition
      • CompositionTrace
      • ConfidenceBand
      • ConnectionCredential
      • ConnectionSubscription
      • ContentResponse
      • ContextCreateRequest
      • ContextId
      • ContextOwnerRef
      • ContextPanorama
      • ContextResolution
      • ContextRow
      • ContextRowWithCounts
      • CorrelationId
      • CreateCogmapOutcome
      • CreateCogmapRequest
      • CreateInvitationRequest
      • CreateRequestBody
      • CreateReviewBody
      • CreateSubscriptionRequest
      • CredentialVerification
      • DataArtifactId
      • DeleteResponse
      • DemoteAdminRequest
      • DeviceOverrides
      • DiscouragedOpenMetaKey
      • DispatchTickRequest
      • DispatchTickResponse
      • Disposition
      • DocTypeDescription
      • DocTypeSummary
      • DriftSweepRow
      • EdgeFacetRow
      • EdgeFacetSetRequest
      • EdgeFacetsResponse
      • EdgeFilter
      • EdgeId
      • EdgeKind
      • ElementEvent
      • ElementKind
      • EmbedDispatchSummary
      • EmbeddingStatus
      • EnforcementMode
      • Entitlements
      • EntryBounds
      • ErasureExecuteRequest
      • ErasureExecuteResponse
      • ErasureSurveyRequest
      • ErasureSurveyResponse
      • ErasureTargetOutcome
      • ErrorBody
      • ErrorDetail
      • ErrorDetails
      • EventCursorResponse
      • EventId
      • EventTrail
      • ExactArm
      • ExactHit
      • Extent
      • FacetAck
      • FacetPredicate
      • FacetRetractAck
      • FacetSetRequest
      • FinalizePayload
      • FoldRelationshipRequest
      • GrantConnectionReachRequest
      • GrantOutcome
      • GrantSpec
      • GraphEdgeRow
      • GroupKeyMeta
      • HealthResponse
      • HomeCogmap
      • HomeContext
      • IdKind
      • IdProvenance
      • IdSet
      • IdpRevocation
      • IngestCreateResponse
      • IngestDelta
      • IngestEnded
      • IngestPayload
      • IngestState
      • InheritedReadGrant
      • InheritedShare
      • InputSource
      • Intention
      • InvitationStatus
      • InvitationTokenRequest
      • InviteeInvitation
      • InvocationAck
      • InvocationActRow
      • InvocationCloseAck
      • InvocationId
      • InvocationSummary
      • InvocationView
      • IssueMachineRequest
      • IssuedMachineCredential
      • JoinRequest
      • JoinRequestStatus
      • JoinRequestWithProfile
      • KindOwnerInput
      • LedgerRef
      • LedgerRefKind
      • LedgerRefRel
      • LedgerRefTarget
      • LensId
      • LineageNode
      • MachineClient
      • ManagedMeta
      • MatchLocation
      • MaterializeAck
      • MaterializeDelta
      • MaterializeRequest
      • MergePolicy
      • MetaUpdatePayload
      • NarrowedBy
      • NodeHome
      • OpenInvocationRequest
      • OpenMetaConvention
      • OrdOp
      • OrphanNode
      • OtherAuthorEdge
      • OtherAuthorEdgeProperty
      • OutcomeDeclaration
      • PendingInvitationCounts
      • PlanRefusal
      • PlanRefusalDetails
      • Polarity
      • Profile
      • ProfileAuthLink
      • ProfileId
      • ProfileUpdateRequest
      • ProfileWithEntitlements
      • PromoteAdminRequest
      • PropertyId
      • PropertyOp
      • PropertyPredicate
      • ProvenanceSource
      • ProvisionConnectionRequest
      • ProvisionMachineRequest
      • PublicSystemSettings
      • QuantityScale
      • QueryResponse
      • QueueCount
      • ReassignAck
      • ReassignContextOutcome
      • ReassignContextRequest
      • ReassignResourceRequest
      • RebindMachineRequest
      • ReblockCandidate
      • ReblockOutcome
      • ReblockReceipt
      • ReblockRequest
      • ReblockScope
      • ReblockSummary
      • ReconcileAutoJoinOutcome
      • ReconcileCogmapRequest
      • ReconcileEdge
      • ReconcileEdgeTombstone
      • ReconcileEntry
      • ReconcileOutcome
      • ReconcileTelos
      • ReconcileTelosBlock
      • ReconcileTombstone
      • RedactedEventFields
      • ReembedRequest
      • ReembedSummary
      • Refusal
      • RefusalReason
      • RegionDisclosure
      • RegionHit
      • RegionId
      • RelationshipAck
      • RelationshipTarget
      • RemoteConnection
      • RemoveMemberOutcome
      • RenameContextOutcome
      • RenameContextRequest
      • ResidualBucket
      • ResidualContext
      • ResidualGroups
      • ResidualOwnedReach
      • ResourceAnnotateRequest
      • ResourceConnections
      • ResourceCreateRequest
      • ResourceErasureExecuteRequest
      • ResourceErasureExecuteResponse
      • ResourceErasurePlan
      • ResourceErasureRefusalReason
      • ResourceErasureSurvey
      • ResourceErasureSurveyRequest
      • ResourceFacetRow
      • ResourceFacets
      • ResourceFacetsResponse
      • ResourceFilter
      • ResourceGrantBody
      • ResourceHit
      • ResourceId
      • ResourceLineage
      • ResourceListResponse
      • ResourceRevokeBody
      • ResourceSection
      • ResourceSortField
      • ResourceUpdateRequest
      • ResourceView
      • RestoreContextOutcome
      • RetireContextOutcome
      • ReturnSpec
      • RetypeRelationshipRequest
      • ReviewRequestBody
      • ReviewRequestWithProfile
      • RevokeOutcome
      • RevokePrincipalBody
      • ReweightRelationshipRequest
      • RotateSecretRequest
      • ScoreKind
      • Scoring
      • SearchParams
      • SearchReason
      • SearchResponse
      • SearchResultRow
      • SearchScope
      • SearchScopeInfo
      • SegmentInfo
      • SegmentedBegin
      • SegmentedBeginResponse
      • SetToolManifestRequest
      • SetWebhookEventsRequest
      • ShapeDeclareRequest
      • ShapeEmptiness
      • ShapeId
      • ShapeView
      • ShareContextOutcome
      • ShareContextRequest
      • SlackDisconnectRequest
      • SlackDisconnectResponse
      • SlackDisconnectedPrincipal
      • SliceRequest
      • SortOrder
      • StageDisposition
      • StageInput
      • StageInputTrace
      • StageName
      • StageNode
      • StageOutput
      • StageRelation
      • StageResult
      • StageTrace
      • Standing
      • StandingShape
      • Subscription
      • SubscriptionOverride
      • SubscriptionSelector
      • SystemAccessDetails
      • SystemSettings
      • TeamCreateRequest
      • TeamDetail
      • TeamInvitation
      • TeamMemberDetail
      • TeamMemberRow
      • TeamMemberSource
      • TeamRole
      • TeamRow
      • TeamSpec
      • TeamUpdateRequest
      • Territory
      • TerritoryKind
      • TerritoryOverview
      • UnbindTeamOutcome
      • UnshareContextOutcome
      • UpdateSettingsRequest
      • VaultConfig
      • ViaEntry
      • WideArm
      • WideHit
  1. playbooks

Self-host Temper with a SAML IdP

For operators — anyone running a self-hosted Temper deployment whose identity provider
speaks SAML 2.0. This covers native SAML single sign-on: Temper fronts your SAML Identity
Provider (IdP) with a minimal OAuth 2.0 Authorization Server (AS) built into Temper. Your SAML
IdP authenticates the user; the Temper AS mints a short-lived EdDSA-signed Temper JWT that
temper-api trusts.
By the end you will have a Temper instance in Temper-AS mode — your SAML IdP authenticating
users, the built-in AS minting tokens both surfaces validate, CLI and (optionally) UI login
flowing through SAML, MCP clients connected, and IdP groups mapped to Temper teams and roles.
Use this when your organization's IdP speaks SAML 2.0 (e.g. Okta, Entra ID, PingFederate,
Shibboleth) and you want a native SP integration rather than an OIDC bridge. For the OIDC
bridge through Okta, see Self-host with Okta.
Doing a full ground-up enterprise install? This playbook is one phase. For the single
end-to-end sequence (deploy → SAML → org → agents) see
enterprise install.
This playbook is the operator runbook. For the security model it implements — how
tokens are verified, the authorization boundary, and where it is enforced — see
The Trust Boundary. For the auth-identity contract this mode
configures, see Auth identity.

Prerequisites#

A base Temper deployment. This page assumes you have completed
Self-hosting Temper through the non-auth steps. SAML replaces the
Auth0/OIDC auth provisioning with the Temper AS; everything else (Neon, Vercel, routing,
verification mechanics) is shared.
The auth-identity contract. A Temper instance validates tokens from exactly one issuer
against one audience set, shared by its HTTP and MCP doors. In SAML mode the Temper AS is that issuer, and the agreement rules
differ from an external-IdP install. Read Auth identity for
the contract and the rules the server enforces at boot.

How it works#

Browser ──(1)──▶ /oauth/authorize ──▶ /oauth/saml/login ──(2)──▶ SAML IdP
                                                                     │
   ┌───────────────(4) code ◀── /oauth/saml/acs ◀──(3) signed assertion
   ▼
/oauth/token ──(5) EdDSA JWT ──▶ temper-api  (validates via /oauth/jwks, JIT-provisions the profile)
1.
The CLI/UI starts an OAuth authorization-code + PKCE flow at /oauth/authorize.
2.
Temper redirects to your SAML IdP (SP-initiated).
3.
The IdP posts a signed assertion back to the AS's ACS endpoint.
4.
The AS validates the assertion, maps it to claims, and issues a one-time code.
5.
The client exchanges the code at /oauth/token for an EdDSA-signed access token.
temper-api validates it against the AS's published JWKS and just-in-time provisions the
profile.
The AS is SP-initiated only, supports a single active IdP per instance, and maps a
persistent NameID (or a configured stable-id attribute) to the token sub. A validly
signed assertion implies email_verified: true.

Quickstart with temper admin saml (recommended)#

Rather than hand-assembling the keys, environment, and SQL documented in the sections below,
an operator working from a repo checkout can generate them with the temper admin saml
command group. It is an emitter: it prints the exact env bundle and SQL (or writes them with
--env-out / runs them with --apply), keeping the AS↔API shared values (AS_AUDIENCE ==
AUTH_AUDIENCE, AUTH_ISSUER == AS_ISSUER, the one INTERNAL_RECONCILE_SECRET,
AUTH_PROVIDER_NAME == saml:<idp-key>) consistent by construction. The sections that follow
remain the authoritative reference and the manual fallback.
1.
Provision keys + env + the IdP row — before anyone can log in:
Omit flags for interactive prompts, or add --no-interactive for a scripted run. It
generates the Ed25519 signing key (AS_SIGNING_KEY_PKCS8), AS_SIGNING_KID, and a strong
INTERNAL_RECONCILE_SECRET, then emits the full env bundle and the kb_saml_idp INSERT to
stdout. --env-out .env.saml writes the env (mode 0600 — it holds the private key); --apply
runs the SQL against $DATABASE_URL. Paste the env into both Vercel functions and deploy.
The bundle carries no MCP settings: MCP_AUDIENCE, MCP_CLIENT_ID, and the MCP client's
AS_CLIENTS entry are added by hand — see
Connect MCP clients. Pass the MCP client
as one more --client <mcp-client-id>=<callback> (repeatable) to have it in the emitted
AS_CLIENTS from the start.
2.
Map IdP groups to teams — after the teams exist (see the org-bootstrap playbook):
Creates the mapping through the admin API, as a system admin's act recorded on the admin
ledger (saml_group_mapping_changed). Onto temper-system or the gating team a mapping is
watcher only, and the IdP reconcile confers no more there whatever a mapping says: give a
higher role on either team directly (temper team add-member, as a system admin), so a spoofed
assertion cannot carry it. Elsewhere the ceiling is maintainer: an owner role, or an owner,
maintainer or member role onto a team with the gating team or an auto-join team beneath it, is
refused unless you add --confirm-elevated. A watcher mapping never needs it. --from-seen reads kb_saml_seen_groups so you can add mappings
reactively. temper admin saml unmap-group --idp-key <acme-okta> engineering +engineering
removes a mapping (also recorded). Memberships it already conferred stay until each member's
next login, when the IdP reconcile removes those no remaining mapping confers.
3.
Verify:
Confirms AS metadata/JWKS are reachable, that you resolve as a system admin (a missing
gating_team_slug otherwise fails silently with 403s), and — with --db — that exactly one
active kb_saml_idp row exists.
Ordering. SAML setup brackets the org-bootstrap playbook: run
provision + deploy + apply the IdP row before the first admin can log in, then run the
org-bootstrap (which creates the teams), then run map-group after those teams exist. See
that playbook's interleave note.

Register Temper as an SP with your IdP#

In your IdP, create a new SAML application ("SP") with:
SettingValue
ACS (Assertion Consumer Service) URLhttps://<instance>/oauth/saml/acs
SP Entity ID / Audiencea stable URI you choose, e.g. https://<instance>/saml/metadata
NameID formatpersistent (recommended) — becomes the token sub
Sign assertionsyes (both the <Response> and the <Assertion> must be signed)
Add two attribute statements to the assertion:
an email attribute (e.g. email) — becomes the token email.
a stable identifier attribute (e.g. uid) — the fallback for sub when the NameID is
not persistent.
Temper publishes its SP metadata at https://<instance>/oauth/saml/metadata for import into
IdPs that accept SP metadata XML.

Configure the active IdP (kb_saml_idp)#

The IdP configuration lives in the database, not env. Insert exactly one active row (flip
is_active to rotate to a replacement). To roll the IdP's signing certificate without an
authentication outage, see Rotate the IdP's signing certificate
below — that is a different operation and it does not involve is_active:
Point email_attr at an attribute your directory admins control. Temper treats the email a
signed assertion carries as verified, and refreshes the stored address from it at every sign-in.
That verified address decides who may redeem a team invitation and which existing profile a new
sign-in joins. If people can edit the attribute themselves in your IdP (some directories allow
self-service edits to secondary profile fields), they can claim an address that is not theirs.
Temper also treats addresses differing only in ASCII letter case as one address; if your mail
host gives Bob@corp and bob@corp to different people, they will be treated as the same person.
Only ASCII letters are folded: José@corp and josé@corp stay two different addresses, so an
invitation must use the exact spelling of any non-ASCII letters in the invitee's address.

Rotate the IdP's signing certificate#

Your IdP will re-key on its own schedule, and the SAML ACS is the only human authentication door on
an AS-mode instance. kb_saml_idp therefore holds two certificate slots: idp_cert and
idp_cert_secondary. An assertion signed by either is accepted, and that overlap is what lets
the IdP cut over whenever it likes instead of at a moment you have to coordinate.
idp_cert_secondary is NULL outside a rotation. Requires migration 20260827000010; on an
instance that has not run it the column does not exist and step 1 fails saying so.
[!IMPORTANT]
Paste the PEM with real line breaks. A plain SQL literal does not interpret \n — under the
default standard_conforming_strings you get the two characters, not a newline, and a
certificate in that shape is not usable. Use a dollar-quoted literal, as the examples below do,
or paste the PEM across real lines. A slot that does not hold a usable certificate is refused by
a constraint on write, so you will hear about it here rather than at step 3.
1. Add the incoming certificate.
2. Check that what landed is the certificate you meant, by fingerprint. This is the step that
catches a wrong or truncated paste, and it matters because nothing later will: logins are still
being signed by the outgoing key, so a login test at this point passes no matter what is in the
second slot. Compare against the fingerprint your IdP publishes.
Sign in once as well, to confirm step 1 broke nothing. To undo: SET idp_cert_secondary = NULL.
3. Let the IdP cut over. Do this at the IdP, on its schedule. Logins keep working throughout,
signed by whichever key the IdP happens to be using, and they keep working if it cuts back.
4. Drop the outgoing certificate.
The AND matters: without it, running this a second time would try to move a NULL into
idp_cert. Steps 1–3 are each reversible on their own. Step 4 is not — it discards the
outgoing certificate, and putting it back means having kept a copy outside the database. Keep one
until you are sure.
Step 4 stops the retired certificate being accepted at that write, with no cache to wait out —
loadActiveIdp reads the row on every request. That bounds new logins only. Sessions already
issued continue: an access token for up to AS_ACCESS_TTL_SECONDS, and a refresh chain for up to
AS_REFRESH_CHAIN_MAX_SECONDS from its last full login. If you are rotating because a signing key
was compromised, step 4 is not the control you need — revoke the affected principals, which ends
their chains in the same transaction (see Deactivating an account).
[!NOTE]
Two slots widen the accepted signers by exactly one named certificate, and only for this IdP.
A certificate belonging to some other IdP, or to none, is refused during an overlap window exactly
as it is outside one, and the instance still has a single active IdP throughout.
temper admin saml verify --db checks that there is exactly one active IdP row. It does not
inspect either certificate, so it stays green through every step above, including a rotation you
have half-finished. It is not a check on the rotation.

Map IdP groups to Temper teams and roles#

Temper reconciles team membership from SAML-asserted groups on each login. This is
eventual, not immediate: a user removed from a group keeps access until their session expires
and they next log in.
Reconcile only ever manages source='idp' memberships. Native memberships (added in-app or
by any approval door — join-request review, direct grant, promotion, reactivation — and by
temper admin access reconcile-auto-join) are never touched — if a user is already a native
member of a team, the IdP reconcile skips that (team, user) pair for them entirely.
Group
provisioning is purely authorization; it never creates, deletes, or deactivates the profile
itself. Note the inverse direction on a team that is also an auto-join team: approval (and
reconcile) writes a native row there, and from then on the IdP's role assertion for that
(team, user) pair is skipped — a group-mapped role change will not apply until the native row
is removed.
1.
Tell the SP which assertion attribute carries the group list:
Leave groups_attr NULL to keep authentication-only behavior (no membership changes).
2.
Map groups to (team, role) with the admin door. Teams must already exist. Two groups mapping
to the same team collapse to the strongest role (owner > maintainer > member > watcher):
Each mapping is a system admin's act, recorded on the admin ledger. The ceiling is
maintainer: an owner role, or an authoring role onto a team with a pool (the gating team or
an auto-join team) beneath it, is refused unless you add --confirm-elevated (for example
--role owner --confirm-elevated). Onto temper-system or the gating team only --role watcher
is accepted. Re-running
an identical mapping changes nothing. temper admin saml unmap-group removes one.
Owning the gating team does not make anyone a system admin: that is the governance grant
(temper admin promote). The first admin still requires the SQL bootstrap step; SAML does
not bootstrap the system.
Unmapped asserted groups are ignored for provisioning, but they ARE recorded in
kb_saml_seen_groups (with first/last-seen) so you can discover what the IdP actually sends and
add mappings reactively — the mapping table never needs to be pre-populated:
Removal semantics. Removing a group from the assertion revokes the corresponding idp
membership on the next login. The distinction matters: if the assertion omits the groups
attribute entirely
(e.g. a transient IdP misconfiguration), reconcile is skipped and no
memberships are revoked; only an assertion that carries the attribute with no values ("in no
mapped groups now") revokes all of the user's idp memberships.

Seeing when each user's reach was last reconciled#

Because reconcile runs on login, how current a user's idp memberships are depends on
when they last signed in — and, if the assertion omitted the groups attribute you
configured, on whether there was anything to reconcile against. Both are recorded per user
in kb_saml_principal_reconcile, and vw_saml_reconcile_staleness reads them together with
the reach each user actually holds.
This applies only once groups_attr is set. With it left NULL the IdP is authentication-only,
no team membership is derived from it, and no reconcile is attempted or recorded — so these
tables stay empty, which is the correct reading rather than a gap:
Users whose reach predates the record show last_reconciled_at as NULL: the column is not
backfilled, because there is nothing on disk to backfill it from and a synthesized timestamp
would report agreement that was never performed. They take a real value on their next login.

Environment variables#

Authorization Server (temper-cloud / the API deployment)#

Generate an Ed25519 signing key:
VariableValueNotes
AS_ISSUERhttps://<instance>The AS issuer URL. Setting this flips the instance into AS mode (it serves AS metadata/JWKS instead of Auth0).
AS_AUDIENCEhttps://<instance>/apiAudience claim minted into tokens for API flows (must equal the temper-api AUTH_AUDIENCE).
AS_SIGNING_KEY_PKCS8(PEM contents)Ed25519 private signing key (PKCS#8 PEM). Keep secret.
AS_SIGNING_KIDe.g. as-2026-07Key id published in the JWKS.
AS_CLIENTS(JSON, see below)Required allowlist of client_id → [redirect_uris]. Without it every /oauth/authorize is rejected (fail-closed).
AS_ACCESS_TTL_SECONDS900 (default)Access-token lifetime.
AS_REFRESH_TTL_SECONDS2592000 (default, 30d)Refresh-token lifetime. Slides on every rotation.
AS_REFRESH_CHAIN_MAX_SECONDS7776000 (default, 90d)Absolute lifetime of a refresh chain, from the last full SAML login. Rotation never moves it, so this — not the two TTLs above — is the bound on how long IdP-removed reach can persist. See Limitations.
AS_SAML_ASSERTION_MAX_SECONDS3600 (default, 1h)The widest assertion validity window your IdP issues — read it off the IdP, not off Temper. It is the floor below which a consumed assertion is never forgotten, so the retention sweep cannot delete a replay row that could still be replayed. Too large costs a little storage; too small re-opens replay. A value that is present but not a usable number of seconds fails the sweep rather than substituting the default — rows stay on disk until you fix it; unset or blank uses the default. Read by temper-api, not by the AS — if you run the two as separate processes, set it on temper-api. See What is kept, and for how long.
AS_REFRESH_REPLAY_GRACE_SECONDS10 (default)How soon after a rotation a client may present the spent refresh token again and be treated as a retry rather than a thief. Later than this and the whole chain is ended. 0 ends the chain on any replay; the widest value honoured is 3600. See Watch for replayed refresh tokens.
AS_CLIENTS registers the exact redirect URIs each client may use (exact string match — this
is the control that prevents authorization-code exfiltration):
{
  "temper-cli": ["https://<instance>/api/auth/cli-callback"],
  "temper-ui":  ["https://<app-url>/auth/callback"],
  "temper-desktop": ["https://<instance>/api/auth/cli-callback"]
}
temper-desktop is the desktop app's own public client — the registration a deployment
publishes to the app through desktop_client_id in the [auth] provider entry (see the
config reference). Its redirect is the same relay the CLI
uses; the app's sign-in opens the system browser and receives the code on a local loopback
port carried through that relay.

temper-api#

Point temper-api at the AS as its single issuer:
VariableValue
JWKS_URLhttps://<instance>/oauth/jwks
AUTH_ISSUERthe same value as AS_ISSUER
AUTH_AUDIENCEthe same value as AS_AUDIENCE
MCP_AUDIENCEhttps://<instance>/mcp — the MCP resource indicator. Set it on the same project/processes as everything above; see Connect MCP clients
AUTH_PROVIDER_NAMEsaml:<idp-key> (e.g. saml:acme-okta) — namespaces the JIT auth link. Max 32 chars.

MCP relay credential (optional, recommended)#

The MCP function forwards every tool act to this API over HTTPS, carrying the caller's own
bearer plus a service credential header the API checks before attributing the act to the MCP
surface (@mcp). Set TEMPER_MCP_SERVICE_SECRET to the same value on the API and the MCP
function deployments.
VariableWherePurpose
TEMPER_MCP_SERVICE_SECRETAPI + MCP function (shared)Shared secret gating MCP attribution: only requests carrying it may claim the relay's attribution carrier. Unset on the API ⇒ the carrier is never trusted — relaying still works, but every relayed act attributes to the direct (@web) surface. Must differ from every other shared secret the API configures (the API refuses to boot on overlap), and must be at least 16 characters (the API refuses to boot on a weak one). Generate with openssl rand -base64 32.
Pin the relay's target. The MCP function relays to whatever TEMPER_API_BASE_URL names; that
variable should be pinned to this deployment's own API URL in the function's environment (and ideally
unset everywhere else). The relay sends the caller's bearer plus the service credential to that
origin on every tool act, and while the pool refuses redirects, the origin it was pointed at is
trusted by construction — treat the variable as a credential-adjacent value, not a tuning knob.
What the MCP function's environment holds. The function never reads DATABASE_URL. It
reads its own configuration: the auth identity, CORS_ORIGINS, the blob variables (it reads the
blob token itself, to serve the blob tools), TEMPER_API_BASE_URL, TEMPER_MCP_SERVICE_SECRET,
TEMPER_EDGE_PROXY_SECRET, the discovery variables, and the telemetry variables. The complete
lists are McpServerConfig::from_lookup and DiscoveryConfig::from_env in
crates/temper-mcp-server. Vercel scopes environment variables to a project and an environment,
not to a function, so the API's other shared secrets (INTERNAL_RECONCILE_SECRET, SLACK_*, the
sweep salt) are also in its process environment, and a compromise of the MCP function would
yield them. If your platform scopes variables per function, give the MCP function only what those
two readers name.

Group provisioning#

These gate the internal reconcile call the AS makes to temper-api before minting a token. Set
INTERNAL_RECONCILE_SECRET to the same value on both the AS and the temper-api deployment
(they share a Vercel project env). If unset, the reconcile endpoint is disabled and no group
provisioning occurs (authentication still works).
Why a shared secret rather than an origin/IP allow-list, and the endpoint's bounded blast
radius, are explained in The SAML reconcile channel.
VariableWherePurpose
INTERNAL_RECONCILE_SECRETAS + API (shared)Shared secret gating the internal reconcile call. Same value on both. Unset ⇒ reconcile disabled, no group provisioning.
INTERNAL_RECONCILE_URLASFull URL of the temper-api /internal/saml/reconcile endpoint the AS calls before minting (e.g. https://<your-api-origin>/internal/saml/reconcile).
INTERNAL_RESOLVE_URLASFull URL of the temper-api /internal/principal/resolve endpoint (e.g. https://<your-api-origin>/internal/principal/resolve). Gated by the same INTERNAL_RECONCILE_SECRET. The AS calls it to learn which profile a login belongs to, so an administrator's revoke can end that principal's refresh chains. Unset ⇒ chains are minted without an owner and are bounded by AS_REFRESH_CHAIN_MAX_SECONDS alone.

Slack account link (optional)#

These are needed only if you run the @temper mention agent. Leave all three unset and the
link endpoint is disabled — everything else works unchanged.
The flow makes temper an OAuth client of your own AS: it authorizes as
SLACK_LINK_CLIENT_ID and is redirected back to <PUBLIC_BASE_URL>/api/auth/slack/callback.
That redirect URI must therefore appear in that client's AS_CLIENTS entry — AS_CLIENTS is
an exact-match allowlist and unset is fail-closed, so an unregistered URI is refused by the AS
before temper sees the request.
VariableWherePurpose
SLACK_LINK_CLIENT_IDAPIThe client_id the link flow authorizes as. Must be present in AS_CLIENTS, with <PUBLIC_BASE_URL>/api/auth/slack/callback among its redirect URIs.
SLACK_LINK_SECRETAPI + mention agent (shared)Shared secret gating the agent's /internal/slack/link-state call. Same value on both. Unset ⇒ link endpoint disabled.
PUBLIC_BASE_URLAPIThis instance's public origin (e.g. https://<instance>). The callback redirect_uri is derived from it.

Configure the CLI#

Run the guided setup and pick the Temper AS (native SAML) provider:
Or non-interactively:
This writes an [[auth.providers]] block with provider = "temper-as",
client_id = "temper-cli", authorize_url = https://<instance>/oauth/authorize,
token_url = https://<instance>/oauth/token, and
callback_url = https://<instance>/api/auth/cli-callback. The existing PKCE + loopback login
flow is issuer-agnostic — no other CLI change is needed. temper auth login then authenticates
through SAML.

Configure the UI (optional)#

The SvelteKit UI logs in against the AS as a public PKCE client (no client secret). Set:
OIDC_DISCOVERY_URL points the UI at the AS's RFC 8414 metadata (the AS does not serve
/.well-known/openid-configuration). Ensure temper-ui's <app-url>/auth/callback is listed
in AS_CLIENTS. OIDC_PUBLIC_CLIENT=true is required for this secret-less path — without it,
the UI fails fast at startup rather than silently running with no client secret.
Single-origin ACS and CSRF (SAML only). In the single-origin topology, temper-ui
reverse-proxies /oauth to the API, so the SAML ACS is reached at <app-url>/oauth/saml/acs.
The SAML HTTP-POST binding delivers the assertion as a browser-submitted form POST from
the IdP's origin
— a legitimately cross-origin POST that SvelteKit's built-in origin CSRF
check would otherwise reject with 403 Cross-site POST form submissions are forbidden before
the proxy could forward it. temper-ui handles this: the built-in check is disabled and the
equivalent origin guard is re-implemented in hooks.server.ts (scoped to the UI's own
routes), after the proxied surface — including the ACS — has already been short-circuited
upstream. The ACS POST is authenticated by the SAML layer itself (signature, audience,
destination/recipient, replay guard), not by an Origin match. No operator action is
required
— this is built in. The OIDC path does not hit this at all: its callback
completes as a GET redirect, which CSRF does not touch.

Connect MCP clients (Claude Desktop / Claude Code)#

The remote MCP server (/mcp) is served from the same deployment and authenticates against
the Temper AS via OAuth. MCP clients find the AS through the MCP server's RFC 9728
protected-resource metadata, read the AS's RFC 8414 metadata, and register themselves
dynamically (DCR)
— current Claude Code/Desktop ignore a client-side client_id and fall back
to DCR regardless. On a SAML instance the AS metadata's registration_endpoint is
https://<instance>/oauth/clients. For a public MCP client it mints nothing and stores nothing:
it answers with the one pre-registered MCP client_id and echoes back only the requested
redirect URIs that client is already allowed. The allowlist is never widened by a registration,
so the /oauth/authorize open-redirect protection is unweakened. To enable it:
1.
Set the MCP resource indicator.
MCP_AUDIENCE=https://<instance>/mcp
AS_ISSUER stays the authorization-server issuer (https://<instance>) — an issuer is not
a resource.
AS_AUDIENCE and AUTH_AUDIENCE stay the API/default audience (https://<instance>/api).
MCP_AUDIENCE names the MCP resource. It is independent of AS_AUDIENCE — they need not
be equal, and on this shape they are not. It must be a URI.
Every participating function or process receives the same value: whatever serves
/oauth/* (the authorization server, which serves the resource), whatever serves /mcp
(which advertises it) and whatever serves /api (which accepts it — the MCP server relays
every tool call to the API with the caller's own token). With project-level env that is one
variable; with per-function env (see MCP relay credential)
declare it on all three. Redeploy afterwards — a function's environment is bound to its
deployment.
Omitting it keeps the single-audience fallback: the MCP server advertises the API audience
as its resource. Strict MCP clients require the advertised resource to equal the MCP server
URL or its origin, so with AUTH_AUDIENCE=https://<instance>/api they refuse to sign in.
Both doors accept a token for either audience — see
The Trust Boundary. The split is for resource discovery, not
a privilege boundary between HTTP and MCP.
2.
Set MCP_CLIENT_ID to a client id of your choosing, <mcp-client-id> (conventionally
temper-mcp), wherever /oauth/* is served. It must also be a key in AS_CLIENTS. Without
it, registration answers 503 temporarily_unavailable.
3.
Register each remote client's callback under that client in AS_CLIENTS. Start from the
value the deployment currently has — read it where you set it (on Vercel, the project's
environment variables page, or vercel env pull). Do not regenerate it with
temper admin saml provision: that also mints a new signing key and reconcile secret. Add one
key, or append to it if it exists, and preserve every entry already there. For an instance
configured as in this playbook the result looks like:
{
  "temper-cli":     ["https://<instance>/api/auth/cli-callback"],
  "temper-ui":      ["https://<app-url>/auth/callback"],
  "temper-desktop": ["https://<instance>/api/auth/cli-callback"],
  "<mcp-client-id>": [
    "<existing-callbacks>",
    "<remote-client-callback>"
  ]
}
plus any other client your instance already lists (for example the Slack-link client).
Edit, never replace. AS_CLIENTS is the whole allowlist for every client on the
instance. Pasting an example over it silently removes whichever callbacks the example lacks,
and those sign-ins fail.
Remote (HTTPS) callbacks match exactly — scheme, host, path, trailing slash. Take the
value from the remote client's own public documentation; for the Claude Desktop / web
connector those are https://claude.ai/api/mcp/auth_callback and
https://claude.com/api/mcp/auth_callback.
Loopback callbacks are matched by path, port and loopback host ignored (RFC 8252 §7.3),
because native clients such as Claude Code listen on an ephemeral port. A port-less entry
with the client's callback path — http://127.0.0.1/callback for Claude Code — matches
http://127.0.0.1:<random>/callback and its localhost / [::1] spellings. Loopback
matching never applies to an HTTPS callback. A loopback entry with the wrong path is the
loopback equivalent of an inexact HTTPS callback.
A callback that is not registered is not an error at registration time — it is filtered
out
of the registration response, and the client then fails at sign-in. The check below
catches that first.
4.
Audience/issuer alignment is enforced at boot — you do not have to remember it. The AS
mints iss = AS_ISSUER and, by default, aud = AS_AUDIENCE; both doors validate the one
issuer and the instance's accepted-audience set. If these disagree, the process refuses to
start
and names the offending variable:
AS mintsThe instance validatesEnforced requirement
AS_ISSUERAUTH_ISSUERAS_ISSUER == AUTH_ISSUER, byte for byte
AS_AUDIENCEAUTH_AUDIENCEAS_AUDIENCE == AUTH_AUDIENCE
MCP_AUDIENCE, for a flow that requests itMCP_AUDIENCEmust be a URI; no equality rule
(its JWKS)JWKS_URLJWKS_URL == $AS_ISSUER/oauth/jwks
An authorization request may name its resource; the AS accepts only a member of its served
set (AS_AUDIENCE, plus MCP_AUDIENCE when set), mints it into the token, and keeps it
across every refresh of that session.

Check discovery and registration#

Four deployment-neutral checks, run before anyone tries to sign in. Each uses only public,
unauthenticated endpoints.
Expect:
1.
"resource": "https://<instance>/mcp" — not https://<instance>/api. The API audience here
means MCP_AUDIENCE is unset or has not reached the MCP function.
2.
401 with a WWW-Authenticate: Bearer … resource_metadata="https://<instance>/.well-known/oauth-protected-resource"
header.
3.
"client_id": "<mcp-client-id>" and "redirect_uris": ["<remote-client-callback>"] — the
requested URI, echoed as sent (a loopback callback comes back with its port). An empty
redirect_uris means that callback is not allowed under <mcp-client-id> in AS_CLIENTS:
not an exact match for an HTTPS callback, or no loopback entry with that path. This call
creates nothing; it is safe to repeat.
4.
302 — a redirect to the instance's /oauth/saml/login, the hand-off to your IdP. A 400 means the authorization server
refuses the request: requested resource is not served by this authorization server when
MCP_AUDIENCE has not reached the functions serving /oauth/*, unregistered client_id or redirect_uri when check 3's callback is wrong there. This call records a short-lived pending
sign-in that expires unused.
These establish discovery, registration, and that the authorization server will mint the MCP
resource. They do not prove the API accepts it: a complete check signs in from the client —
through your SAML IdP — and runs one read-only tool call, which is relayed to the API.
Then add the server to Claude Code and authenticate:

Verify#

1.
temper auth login → a browser opens to your IdP; after SAML login the CLI receives a
token.
2.
temper auth status (or any authenticated command) succeeds.
3.
A kb_profiles row and a kb_profile_auth_links row (with
auth_provider = saml:<idp-key>) are created for the user on first login.

Deactivating an account (authn control)#

Team membership is authorization; it does not control whether an account can log in. To
stop an account from authenticating at all — regardless of what the IdP asserts — deactivate
the principal's system access:
A deactivated principal is rejected by the API auth middleware (401) even with a valid
token. This never deletes the profile or its history, and it is independent of SAML group
provisioning (temper admin access reactivate <profile-uuid> restores the prior standing).
Reconcile/deprovisioning of a team never deactivates a principal.
Deactivation is enforced by the shared authorization seam, so both surfaces — temper-api
and temper-mcp — reject a deactivated principal identically. See
The Trust Boundary.

Running it as the applier#

The saml-setup.sh script automates the temper admin saml sequence above from a declarative
profile (saml-profile.yaml) — it loops provision / map-group / verify. Run from a repo
checkout:
Dry-run — prints the commands without executing:
saml-setup.sh --profile saml-profile.yaml --dry-run
Emit only (default) — env bundle + kb_saml_idp SQL, safe to run anytime, no DB writes:
saml-setup.sh --profile saml-profile.yaml
Apply — writes the kb_saml_idp row, applies group mappings, verifies against the live
DB (needs DATABASE_URL + psql; run post-migrate, and after the org-bootstrap teams exist):
DATABASE_URL=postgresql://… saml-setup.sh --profile saml-profile.yaml --apply-db
It needs yq to read the profile and temper on PATH. Emit-by-default and idempotency are
inherited from the underlying temper admin saml commands, not reimplemented by the script. It
is the SAML sibling of system-bootstrap.sh (kept separate so that script stays usable for
Auth0/Okta-OIDC installs) — see enterprise install for how the two
appliers interleave across the full install timeline.

Limitations#

Reconcile-on-login only. Profile attributes refresh when the user logs in; there is
no live deprovisioning.
The bound to state is AS_REFRESH_CHAIN_MAX_SECONDS, not AS_ACCESS_TTL_SECONDS. A session
survives across access-token expiries by refreshing, so the access TTL describes how often a
token is reminted, not how long a session lives. What bounds the session is the chain's
lifetime: every refresh token belongs to a chain whose deadline is stamped at the last full SAML
login and inherited unchanged by every rotation. Once it passes, the only way forward is a fresh
login — which reconciles against the IdP, and brings the user's team reach back into agreement
with what the IdP confers today.
So the figure to give a review board for IdP-side removals is
AS_REFRESH_CHAIN_MAX_SECONDS + AS_ACCESS_TTL_SECONDS — 90 days plus 15 minutes on the
defaults. Lower AS_REFRESH_CHAIN_MAX_SECONDS to shorten it, at the cost of how often your users
re-authenticate.
An administrator's revoke is immediate, and does not wait for any of the above. Revoking or
deactivating a principal ends their live refresh chains in the same transaction as the standing
change, and no later sign-in mints them a new one. This is the path to use when you need a
departure to take effect now; the chain lifetime is the backstop for the case nobody acted on.
What a revoked principal can still do, stated exactly, because "immediate" is easy to
over-read. They can complete a SAML sign-in and receive an access token — deliberately, since
reaching /api/access/review-request to contest the revocation requires one. That token is
refused on every data route, and it is not renewable: no refresh chain is minted for them, so
it expires within AS_ACCESS_TTL_SECONDS and is not carried forward. If you need the sign-in
itself to stop, disable the account at your IdP — that is the control temper does not own.
A principal who has not yet been approved (or whose request was declined) keeps refreshing
normally — also deliberately. Nothing has been taken away from them, and they hold a token in
order to reach the join-request endpoints and ask for access; removing it would make asking
harder, not safer.
[!IMPORTANT]
Upgrading an existing SAML deployment? INTERNAL_RESOLVE_URL is new, and nothing sets it for
you — temper admin saml provision emits it only into a freshly generated bundle. Without it the
AS cannot record which principal a refresh chain belongs to, so an administrator's revoke ends
no chains
and the only remaining bound is AS_REFRESH_CHAIN_MAX_SECONDS. Logins and refreshes
keep returning 200 throughout, so there is no failure to notice.
The signal to look for is the API's standing terminal ended no refresh chains warning when
you revoke someone — but read its ownerless_live_chains field, not merely its presence. That
warning is also the normal outcome for a machine principal and for anyone who simply was not
signed in; a non-zero ownerless_live_chains is the part that means the authorization server
is not recording owners at all. Add the variable, pointing at your API origin's
/internal/principal/resolve, before relying on revoke.
Single active IdP per instance, SP-initiated flows only.
Single issuer per instance: an instance is either an AS/SAML instance (AS_ISSUER set)
or an Auth0/OIDC instance, not both.
Role/team mapping from SAML attributes is available once groups are configured (see
Map IdP groups to Temper teams and roles).

Watch for replayed refresh tokens#

Refresh tokens are single-use: exchanging one revokes it and issues a successor. If a spent
token is presented again, one of two things happened — a client retried an exchange whose response
it never received (or raced two refreshes at once), or someone else has a copy of the chain.
RFC 6819 §5.2.2.3 treats the second as the more likely reading once enough time has passed, and
temper acts on it: the whole chain is ended, so the copy and the original both stop working and the
user signs in again.
AS_REFRESH_REPLAY_GRACE_SECONDS is where you set the line between the two readings. Inside
the window the replay is refused but the chain survives; outside it, the chain is ended.
Ten seconds is the default, and the width is worth understanding before you change it. The server
only ever sees the party that lost a rotation race, and cannot tell whether the one that won was
your user or someone holding a copy — so inside the window it lets the winner keep the session and
records the presentation as benign. Every second of width is a second in which a fresh theft gets
that treatment. What the window buys is the client that had two refreshes in flight at once, which
is one exchange still resolving and takes well under a second. A client that merely lost a response
and retried holds no live token either way, so a narrow window costs it nothing but a row in the
table below.
Raise it if you run clients on unreliable networks and would rather read past those rows — up to
one hour, which is the widest value honoured
; anything larger, negative or non-numeric is read as
a units slip, logged, and replaced by the ten-second default. Set it to 0 for the strictest
reading, where any replay ends the chain.
Either way the event is recorded, so you can answer "has any chain been replayed?" without
having retained logs:
A row means a spent refresh token came back. Rows are not by themselves alarming — a client
that loses a response and retries produces one, so a healthy instance accumulates some. Read
hostile_count first; it is the count of presentations that fell outside the grace window.
An empty result means nothing was recorded. That is not quite the same as nothing having
happened: if the server could not write the record it says so in its logs (could not record or act on a refused rotation), which is the one case where this table and the logs have to be read
together.
ColumnRead it as
profile_handleWho held the chain. NULL if the AS could not record an owner — see the INTERNAL_RESOLVE_URL note above; the replay is still real.
first_replay_ageHow long after the rotation the token reappeared — the age the server judged it on, not a later reading. Seconds is consistent with a client retry, not proof of one: a credential stolen and used immediately also reappears in seconds. Hours or days is consistent with theft, and also with a client that lost a response and retried much later — a CLI whose refresh timed out on its side presents the old token on its next run. Read it with tokens_revoked. When the database committed a rotation but its reply never reached the AS, the client was told temporarily_unavailable, no successor exists, and the row shows tokens_revoked = 0 (a lost success response shows 1, since the successor the client never received was live); the AS also logs the token store did not answer the refresh rotation shortly after rotated_at. That line carries no token or chain identifier, so it can only be matched by time, and its absence proves nothing.
replay_count / hostile_countHow many times it was presented, and how many of those fell outside the grace window. hostile_count = 0 on a chain you did not expect to be racing is still worth a look.
chain_ended / chain_ended_atWhether the chain was ended in response, and when.
tokens_revokedHow many live tokens the ending actually revoked. 0 alongside chain_ended means the chain held nothing live at that moment — it is still ended, and no successor can be minted into it.
A replay ends that chain only — not the principal's other sessions, and not their ability to
sign in again. If you conclude a credential really was stolen, revoke the principal:
That ends every chain they hold and stops the next sign-in from minting a new one — see
Limitations for exactly what a revoked principal can still do.
[!NOTE]
What this view covers: chains issued by this instance from this version onward. Earlier
chains are bounded by AS_REFRESH_CHAIN_MAX_SECONDS and are gone within that window, so an empty
result means "nothing recorded", which becomes "nothing happened" once your longest chain has
turned over.

What is kept, and for how long#

Three tables back the authorization server, and a row lands in one of them on every login. A
daily sweep (/api/as/reap, gated by the same EMBED_DISPATCH_SECRET bearer as the other internal
crons — no separate secret to set) deletes rows once they are past a floor. It deletes at most
50,000 rows per table per night
, so a backlog accumulated before you upgraded drains over as many
nights as that arithmetic gives you rather than in one statement — check count(*) on the three
tables if you want to know how long.
TableA row perDeleted once
kb_saml_replayconsumed SAML assertionAS_SAML_ASSERTION_MAX_SECONDS has passed since the row's stamped expires_at — so never sooner than that long after the assertion was consumed
kb_oauth_flowauthorization-code flow (including abandoned ones)1 day past expires_at
kb_oauth_refresh_tokensissued refresh token30 days past both its own expiry and its chain's chain_expires_at
[!IMPORTANT]
Apply migrations before the first sweep runs. The sweep's indexes and its evidence constraint
ship as a migration and it is built to run with them in place; run it first and it will simply
make less progress per night.
Two of these floors are security properties, not housekeeping.
A kb_saml_replay row is what stops a captured assertion being presented twice. Temper does not
read your IdP's NotOnOrAfter, so the row's own expires_at is an assumption about it rather than a
statement of it — which is why the sweep subtracts AS_SAML_ASSERTION_MAX_SECONDS instead of
trusting that stamp. If your IdP issues assertions valid for longer than an hour, raise this
variable before the first sweep runs.
Leaving it too low deletes assertion ids that are still
replayable; leaving it too high costs you an assertion id and a timestamp per login.
A spent refresh token is kept until its whole chain is dead because that is what makes a stolen
one detectable: a rotated token presented again is recognised however long ago it expired, and the
chain is ended in response. Reaping on the token's own expiry would quietly turn that into an
ordinary "invalid grant".
Detection does end when the row does. A replay of a token whose chain died more than 30 days ago
is answered with a plain invalid_grant, logs nothing and records nothing. Before this sweep
existed nothing was ever deleted, so that reach was unbounded; 30 days past a dead chain is the
bound it now has.
Evidence already recorded in kb_oauth_refresh_replays is a different matter: the sweep never
deletes it, at any age.
It filters those rows out, and underneath that the foreign key is
ON DELETE RESTRICT, so the database refuses the delete even if some future caller forgets the
filter. Nothing you can see through
vw_oauth_refresh_replays is aged out from under you.
Deleting the profile a replay belongs to does remove that row, because it cascades from
kb_profiles — retention and erasure are different acts, and only the first is what this sweep
does.
Every run logs what it deleted per table, including a run that deleted nothing. Server logs are
JSON, so the record looks like this (fields elided):
{"level":"INFO","fields":{"message":"AS retention sweep complete","saml_replay":1204,
 "oauth_flow":880,"refresh_tokens":0,"more_pending":false,"assertion_window_seconds":3600.0}}
more_pending is true when a table stopped because it hit the 50,000-row cap rather than because
it ran out — the next night's run continues from there. assertion_window_seconds echoes the floor
the run actually used, which is the quickest way to confirm a change to
AS_SAML_ASSERTION_MAX_SECONDS reached the process.

Further reading#

The auth-identity contract this mode configures:
Auth identity.
The security model this playbook implements:
The Trust Boundary.
The internal reconcile channel between the AS and the API:
The SAML reconcile channel.
The base deployment this page builds on:
Self-hosting Temper.
The full enterprise install sequence:
enterprise install.
What the architecture fixes vs. what a deployment chooses:
temperkb.io/operating/deployment.
Modified at 2026-11-15 01:09:09
Previous
Self-host Temper with Okta
Next
Send traces to an OTLP backend
Built with