plugin-api/ contains the small set of interfaces shared by core and plugins:
Principal, Event, AuditEvent, and BlobRef are boundary value types.
Business services, database helpers, and format-specific contracts remain in
core rather than expanding plugin-api.
Preserve filing ownership through these values: Event.SystemID and
AuditEvent.SystemID identify system/document work; zero is reserved for genuinely
instance-wide work. A documentless index refresh or approval proposal is still
system-owned. Principal.TokenSystemID is the authenticated token’s binding, not
the browser’s selected context; session principals leave it zero.
Subscriber contract
Handle must be idempotent. Persist a
deduplication key or use a unique database constraint before applying an
observable side effect. Respect context cancellation and return failures so the
job can retry or become visible as dead.
Do network and subprocess work outside a database transaction. Open one short
write transaction only after the external result is available. State needed
after restart belongs in the database or event payload, not a package-level
cache.
Enqueue through jobs.Enqueue(ctx, tx, kind, docID, systemID, payload): the explicit
system must match any document. Zero persists as NULL only for global work.
The outbox inserts jobs without deduplicating them. Resolve metadata and background
actions within the event/document system, rechecking current referenced records
in the writer; a job is not an authenticated cross-system document-link grant.
Minimal shape:
Authenticator contract
(nil, nil) when the request does not use your authentication scheme so
the next authenticator can try. Return an error when your scheme is present but
invalid; silently falling through would allow an authentication downgrade.
An authenticator should resolve the external identity to a Suchi user and
return only the principal fields needed by authorization and audit. Put roles,
group membership, and object policy in the authorization layer rather than in
provider-specific token parsing.
Token authenticators must set TokenSystemID; an external token that leaves it
zero is restricted to original system 1, never all systems. Local tokens also
carry TokenID so mutations can recheck revocation, actor and binding inside the
single writer. Authentication does not grant membership or document permission;
even administrator tokens cannot escape their bound system or an explicit target.
Local issuance uses the caller-owned transaction contract
IssueAPIToken(ctx context.Context, tx *sql.Tx, userID, systemID int64, name, scopes, source string) (string, error).
The API’s TokenIssuer seam has the same signature. Keep pairing consumption,
current membership checks and issuance in that transaction so failure rolls back
consumption and membership removal cannot be bypassed by a later re-admission.
Register more specific authenticators before general local session and token
handling. See plugins/oidc and plugins/local-auth for shipped examples.
Audit sink contract
audit.RegisterSink. The local audit_events table remains the
durable record. Sink delivery is best effort and happens after the database
write, so Emit must be fast or hand work to its own bounded buffer. Never add
document content or plaintext credentials to an audit event.
Package and build wiring
Shipped plugins live in the root module. An external plugin normally has its owngo.mod, depends on plugin-api, and may depend on narrowly required
core packages when it needs database or sandbox helpers. Construct it from a
private distribution entry point; add its module to go.work only while
developing it beside Suchi.
Rebuild and test the final binary after changing plugins. Dependencies become
part of that binary, so prefer the standard library and existing helpers.
Boundaries
- Do not rewrite original CAS blobs. Store a derived blob and update metadata.
- Use
core/sandboxfor external commands rather than rawos/exec. - Keep write transactions free of HTTP, model, and subprocess calls.
- Do not create a plugin interface for behavior owned by one shipped core package.
- Test subscribers directly with a migrated temporary database; test
authenticators with
httptestrequests.
plugins/local-auth, plugins/oidc,
plugins/llm-classifier, and core/pipeline/postingest.