nicool.ai logo
nicool.aiDocumentation

Runtime Guardrails

Required architecture rules for identity resolution, RBAC, skill safety, and performance.

Canonical identity flow

Always resolve contact identity through:

contacts.getOrCreateBySender(senderId)

Do not create contacts or contact-role assignments ad hoc in other runtime functions. That canonical mutation is responsible for preserving the default public role assignment and preventing access drift.

Skill access control

Runtime access decisions must be based on role grants only:

  • contactRoles
  • skillRoleGrants

Do not query skills directly to decide access. Use role-scoped loaders instead:

  • skills.discoverForContact
  • skills.loadForContact

Runtime is read-only for skills

Agent tools must not create or modify skill definitions. Skill writes belong to explicit sync or admin paths such as:

skills.syncCanonical

Migration compatibility

During the current transition period, keep both senderId and contactId on the key runtime tables:

  • inboundSignals
  • agentRuns
  • contactMemory
  • escalationRequests

New writes should include contactId whenever it is available.

Query safety

Use indexed joins in hot paths:

  • by_contact
  • by_role
  • by_skill
  • by_sender
  • by_slug

Avoid full-table scans where an index already exists.

Fail closed

If role resolution fails, or no grants are found, return no restricted skills. Access checks should deny by default rather than trying to recover optimistically.

Observability

Log the events that matter operationally:

  • skill discovery failures
  • skill load failures
  • denied access decisions

The logs should stay concise enough for production diagnosis without turning request traces into noise.