Skip to content
Kavachकवच

Your Own Capabilities: Implementing one

● Intermediate3 min

An implementation is an ordinary type with type Name: Capability, giving a body to each method.

An implementation may need capabilities of its own. This one reads files, and only inside ./inbox, so the agent using it can't read anything else, whatever name it is given:

use std.fs

type InboxError = Missing(name: String) | Denied(reason: String)

capability Inbox {
    fn read(name: String) -> String ! InboxError
}

type InboxFolder: Inbox {
    fn read(self, name: String) -> String ! InboxError uses Fs.read("./inbox") {
        fs.read_text("./inbox/{name}") catch e => match e {
            FsError.Denied(path) => fail InboxError.Denied(reason: "outside ./inbox: {path}"),
            _ => fail InboxError.Missing(name: name),
        }
    }
}

agent Summarizer {
    can Inbox.read, Console

    on summarize(name: String) ! InboxError {
        const text = try Inbox.read(name)
        print("{name}: {text.len()} characters")
    }
}

fn main() ! Error {
    try fs.create_dir("inbox")
    try fs.write_text("inbox/note.txt", "Call the bank on Monday.")
    try fs.write_text("passwords.txt", "do not share")
    const bot = Summarizer.start(Inbox: InboxFolder())
    bot.summarize("note.txt") catch e => print("failed: {e}")
    bot.summarize("../passwords.txt") catch e => print("failed: {e}")
}

The program ran and printed:

kavach run uc-files.kav

note.txt: 24 charactersfailed: Denied(reason: "outside ./inbox: ./inbox/../passwords.txt")
uc-files.kav: Kavach code, then what running it prints

A real payments implementation would need Net to reach the bank. An agent is granted a capability whole (can Payments) or one method at a time (can Inbox.read).