A list of your own
Charter does not know what a screen is. The same charter and the same function decide which tools an assistant is handed.
pnpm add @niscorp/charterA list Charter has never seen
These are the tools an assistant at the box office could call. Nothing in Charter mentions tools.
To govern something with a charter, two things have to be true of it. It is set up as data, as a list of names. And a name that is missing means no.
import { resolvePrincipal, verifyCharter } from '@niscorp/charter';
const tools = ['bookings.find', 'bookings.cancel', 'shows.find', 'refunds.issue'];Roles over it
The roles are written exactly as they are for screens. The desk finds things and cancels bookings. Finance extends the desk and may issue refunds.
const charter = {
desk: ['bookings.*', 'shows.find'],
finance: { extends: ['desk'], allow: ['refunds.*'] },
};Resolve, and hand over
The answer is a set of names. What happens next is up to the thing being governed: here, the assistant is given only the tools in its set.
In Nisc an assistant runs as the user it works for, so it resolves with that user’s roles.
for (const role of ['desk', 'finance']) {
console.log(role + ':', [...resolvePrincipal(charter, tools, [role])]);
}The verifier works on it too
The verifier is as blind to what the names mean. Add a tool that no role selects and it is reported, the same as a screen nobody can reach.
const report = verifyCharter(charter, { actions: [...tools, 'members.export'], data: [] });
for (const issue of report.warnings) console.log(issue.rule + ':', issue.detail);Run it.
The three tools the desk gets, the four finance gets, and the new tool the verifier says nobody can reach.
npx tsx tools.mtsdesk: [ 'bookings.find', 'bookings.cancel', 'shows.find' ] finance: [ 'bookings.find', 'bookings.cancel', 'shows.find', 'refunds.issue' ] orphan: action "members.export" is granted by no role — deployed but unreachable