Forum OpenACS Development: Re: API for AI Agents?!?

Collapse
2: Re: API for AI Agents?!? (response to 1)
Posted by Malte Sussdorff on

Hi Frank,

Thanks for sharing this — it's a well-structured analysis and I think the overall direction is sound. I'd like to build on your ideas with some alternative architectural thinking that comes from practical experience building agent-native systems, most recently our Ignis EHR project (which just won "Best Use of ElevenLabs" at the AI Beavers hackathon for an AI-powered patient intake system operating on FHIR-based healthcare data — including financial data).

I'll start with where I agree, then propose a different implementation path, and finally connect it to a broader alignment framework that I think is critical for anyone building agent interfaces to financial systems.


Where I Agree

Your diagnosis is spot-on in several ways:

Nadella's core insight is directionally correct, even if overstated. SaaS applications are fundamentally CRUD with business logic on top. Agents will increasingly replace the UI layer. Your invoice example — "invoice customer ABC for project XYZ, applying rates from project WXY" — is exactly the kind of operation that agents should handle. The question is how we get there safely.

Your skepticism about determinism vs. "probably right" is well-placed. This matters more than most people in the agent space acknowledge. Financial data doesn't tolerate probabilistic operations. When an agent creates an invoice, the amount must be exactly correct — not "approximately correct based on what the LLM inferred." This constraint shapes the entire architecture.

The existing agent interfaces (ServiceNow Assist, SAP Joule, etc.) are indeed limited. Most of them bolted RAG onto existing APIs and called it a day. That approach fails because the gap between "I found some relevant data" and "I understand the business context well enough to act" is enormous.

Your observation about ]po['s variability is crucial. Different customers use ]po[ in fundamentally different ways. Any agent layer must account for the fact that "project health" means completely different things depending on whether the organization optimizes for margins, scope delivery, resource utilization, or timeline adherence. One-size-fits-all agent interfaces will fail here.


An Alternative Implementation Path

Here's where I'd propose a different approach. Rather than building a new semantic middleware layer on top of the existing data model, I'd suggest exposing the existing Tcl business functions directly as agent-callable tools.

Why? The business logic already exists.

]project-open[ (and OpenACS more broadly) has a massive library of well-documented ad_proc functions that encode decades of business logic. These aren't raw CRUD operations — they're business operations:

  • im_invoice::new doesn't just insert a row; it validates the customer relationship, checks project associations, applies correct tax rules, handles currency conversion, and triggers workflow notifications.
  • im_timesheet::log_hours enforces project membership, validates against project status, applies hourly rate logic, and updates project budget consumption.
  • im_project::update_status respects workflow constraints, triggers notifications, and cascades status changes to dependent objects.

These functions are the "semantic layer" you're looking for — they already exist. What they lack is not semantics but accessibility for agents.

The Tcl API documentation is an undervalued asset

OpenACS's ad_proc documentation system is genuinely excellent. Every public procedure has:

  • A natural-language description of what it does
  • Typed parameter definitions with documentation
  • Preconditions and error cases
  • Package membership (so agents can discover related functions)

This is, essentially, a tool description catalog. An agent with access to this documentation can reason about which function to call far more effectively than one navigating generic OpenAPI/Swagger specs for CRUD endpoints with dozens of optional parameters.

Concrete proposal: Build a CLI tool or MCP server

Instead of a REST semantic layer, I'd build one of these:

Option A: An MCP (Model Context Protocol) server that wraps ]po[ business functions. An MCP server for ]po[ would:

  • Expose business functions as typed tools with descriptions derived from ad_proc documentation
  • Handle authentication and permission checking before any operation reaches the Tcl layer
  • Provide "dry run" semantics at the tool level (your idea, which is excellent)
  • Return structured results that agents can reason about

Option B: A CLI tool that agents can invoke. This is simpler and works with any agent framework (Claude Code, OpenClaw, custom agents). The CLI would:

  • Accept function calls as structured commands
  • Map them to Tcl procedure invocations
  • Return structured results (JSON) with clear error messages
  • Enforce role-based access control at the tool boundary

Both approaches share the same core insight: the agent doesn't need to understand ]po['s data model. It needs to understand ]po['s operations. That's a fundamentally different interface design.

Keep your indicator idea — but as a read layer

Your indicator concept for the read side is strong and I wouldn't drop it. Pre-computed KPIs that abstract over customer-specific variability are exactly what agents need for reasoning about state. An agent asked "should we invoice this project?" needs to know things like:

  • Current budget consumption percentage
  • Unbilled hours and their value
  • Project margin trajectory
  • Outstanding deliverables status

These are indicator-level abstractions, not raw table queries. So the architecture I'd propose is:

  • Read: Indicators (your approach) + the object graph via acs_rels for relationship navigation
  • Write: Business functions exposed as agent tools (my addition)
  • Discover: The ad_proc API documentation as a tool catalog

This gives agents the full loop: understand the current state (indicators), discover what operations are available (API docs), execute operations (business functions), and verify the result (indicators again).


The Critical Missing Piece: Layered Alignment

This brings me to what I consider the most important topic that your post touches on but doesn't fully address: how do you secure financial data when agents are operating on it?

David Shapiro's GATO (Global Alignment Taxonomy Omnibus) framework, which he recently elaborated on in the context of the Moltbook/OpenClaw developments, provides an excellent conceptual map here. GATO identifies three layers of alignment that all need to be addressed. Let me map each one directly onto the ]project-open[ context:

Layer 1: Model Alignment

This is RLHF, Constitutional AI — the work that Anthropic, OpenAI, and others do to make base models refuse harmful requests. It's necessary but not sufficient.

Why it's not enough for ]po[: Agent architectures increasingly use model arbitrage — routing requests to whichever model is cheapest/fastest/most capable for a given task. If one model refuses an operation, the agent can try another. Some models are open-source with safety training removed. You cannot rely on the model layer alone to prevent an agent from creating a fraudulent invoice.

Layer 2: Agent Alignment (where ]po[ has an existing advantage)

This is safety built into the agent architecture itself, independent of which model does the inference. This is where the CLI tool / MCP server approach shines.

]po['s existing permission system maps directly to this layer. OpenACS has object-level ACLs and role-based permissions that are among the most sophisticated in any open-source platform. The acs_permission system can express constraints like:

  • "User X can create invoices but only for projects they manage"
  • "Invoices above €10,000 require workflow approval from a finance role"
  • "No agent can bypass the four-eyes principle on financial transactions"

The key architectural move: enforce these permissions at the tool boundary, not in the model prompt. Don't tell the agent "you're not allowed to approve invoices over €10,000" in a system prompt (that can be jailbroken). Instead, make the tool itself check permissions and return a structured error: {error: "PERMISSION_DENIED", reason: "Invoice approval requires finance_admin role for amounts > 10000", required_action: "Route to human approver via workflow WF-123"}.

This is what Shapiro calls the "Ethos module" pattern — a validation layer that operates independently of the LLM, checking every proposed action against the actual authorization rules before execution.

The existing acs-workflow engine is another alignment mechanism at this layer. Approval chains for sensitive operations (invoice approval, budget changes, project status transitions) should remain human-gated regardless of whether the initiating actor is human or agent. The workflow engine already enforces this — it just needs to be made agent-accessible rather than agent-bypassable.

Layer 3: Network Alignment (the Byzantine Generals problem)

This is the layer that addresses what happens when multiple agents — from different users, departments, or even different organizations — are operating on the same data simultaneously.

This is not a theoretical concern for ]po[. Consider a concrete scenario:

  1. Agent A (working for a project manager) reads project XYZ's timesheet data and determines the project is ready for invoicing.
  2. Agent B (working for a team member) logs 40 additional hours to project XYZ.
  3. Agent A creates the invoice based on its now-stale data.
  4. The invoice is wrong by 40 hours × the applicable rate.

The Byzantine Generals problem in classical computer science asks: how do you achieve coordination when you cannot trust that all participants are honest and reliable? In the agent context, the question becomes: how do you achieve consistent operations when agents have different views of system state, different objectives, and potentially different models with different alignment properties?

The solutions are well-established in distributed systems:

  • Transaction boundaries with optimistic locking (detect and reject stale-data operations)
  • Approval workflows that require human consensus for sensitive operations
  • Audit trails that record not just what happened but which agent initiated it and based on what state
  • Role-based access control that limits the blast radius of any single compromised or malfunctioning agent
  • "Dry run" semantics (your idea!) that let agents preview the effect of an operation before committing

The good news: ]po[ already has machinery for most of this. Workflow engine, permission system, audit logging, transaction management. The work is making it all legible to agents — meaning agents can understand why an operation was rejected, what they need to do instead, and how to route requests that exceed their permissions.

The incentive design Shapiro describes — creating a Nash equilibrium where agents are better off cooperating than defecting — maps onto ]po['s existing organizational structure. An agent that tries to bypass approval workflows gets its operations rejected. An agent that operates within its permissions gets efficient, successful outcomes. The system architecture makes compliance the path of least resistance.


What This Looks Like in Practice

Let me sketch a concrete interaction to make this tangible. Imagine a project manager using an agent with ]po[:

User: "Please invoice customer ABC for project XYZ, applying the hourly rates from project WXY."

Agent's process (invisible to user):

  1. Read (indicators): Query project XYZ indicators — budget status, unbilled hours, margin trajectory. Query customer ABC indicators — payment history, credit status, outstanding invoices.

  2. Discover (API docs): Identify im_invoice::new as the relevant operation. Read its parameter requirements and preconditions.

  3. Validate (dry run): Execute im_invoice::new --dry-run with the computed parameters. The system validates: correct customer-project relationship, rate lookup from WXY succeeds, amount falls within the agent's authorized limit, no conflicting pending invoices exist.

  4. Authorization (agent alignment): The tool layer checks: does this agent's principal (the project manager) have create_invoice permission for project XYZ? Is the amount within the auto-approval threshold, or does it need workflow routing?

  5. Execute or route: If authorized and validation passes, execute and return the result. If it needs approval, create a workflow task and inform the user: "Invoice for €47,230 created as draft. Since it exceeds the auto-approval threshold (€10,000), it's been routed to the finance team for approval via workflow WF-456."

This is deterministic where it matters (the actual financial calculation), intelligent where appropriate (understanding what the user wants and how to accomplish it), and safe by design (permissions and workflows enforce organizational controls regardless of what the model "thinks" it should do).


The Bigger Picture: Why This Matters for the OpenACS Ecosystem

I want to zoom out and make a broader point that I think applies to the entire OpenACS community.

OpenACS was designed around several principles that turn out to be remarkably well-suited to the agent era:

  • Object-level permissions (most web frameworks still don't have this)
  • Typed, documented APIs (the ad_proc system)
  • Workflow engine (approval chains that can gate any operation)
  • Relationship graph (acs_rels — essentially a knowledge graph before that term existed)
  • Package architecture (modular, discoverable functionality)

These aren't legacy baggage — they're structural advantages. Most modern web frameworks would need to build these capabilities from scratch to support agent operations safely. ]po[ and OpenACS already have them. The community invested 20+ years building this infrastructure for human users. The same infrastructure serves agent users, often with minimal modification.

The key insight from our Ignis EHR project — where we build agent-native from the ground up for healthcare data — is that the hard problems aren't "how do I let an agent read and write data." The hard problems are:

  1. Authorization: Who is this agent acting on behalf of, and what are they allowed to do?
  2. Validation: Is this operation consistent with the current system state?
  3. Auditability: Can we trace every agent action back to its principal and its justification?
  4. Determinism: Are financial calculations done by code, not by the LLM?

OpenACS/]po[ already solves problems 1, 3, and partially 2. That's a massive head start.


Practical Next Steps

If I were implementing this, I'd do it in this order:

  1. Start with a read-only MCP server that exposes indicators and the object graph. Zero risk, immediate value — agents can answer questions about project status, find related objects, and generate reports without being able to modify anything.

  2. Add a small set of high-value write operations — the 10–20 business functions that handle 80% of daily operations (create invoice, log hours, update project status, etc.). Each one wrapped with permission checking and dry-run support.

  3. Implement the GATO Layer 2 patterns: Every write operation goes through a validation/authorization gate that is independent of the model. The gate checks permissions, validates against current state, and either executes or routes to workflow.

  4. Extend im_audit for agent operations. The good news: ]project-open[ already has a mature audit module (intranet-audit) with im_audit calls woven throughout the business logic. Every project status change, ticket creation, invoice operation, and timesheet cost entry already passes through im_audit -object_id ... -action after_create/after_update/before_update/before_nuke. The im_audits table records differential changes, timestamps, user_id, and IP address. This covers the "what changed" and "when" questions comprehensively for the supported object types (Projects, Companies, Invoices, Tickets, Expenses, Absences, etc.), and the Enterprise Edition already supports syslog forwarding and write-once device integration for regulatory scenarios. What it doesn't capture — because it was never designed for — is the agent context. The existing audit assumes [ad_conn user_id] is the human who did the thing. In an agent world, you need to answer additional questions: which agent acted, on whose behalf, through which tool call, with what parameters, and why. The data mutation audit is solved; the agent provenance audit is what needs building.

  5. Iterate based on what agents actually do wrong. You'll discover failure modes you didn't anticipate. The dry-run + audit trail combination gives you the data to identify and address them.


Regarding Collaboration

I'm very interested in this space and happy to collaborate. Our work on Ignis (FHIR-based healthcare AI with voice agents) faces many of the same challenges — financial data integrity, regulatory compliance, multi-agent coordination — just in the healthcare domain instead of project management. The architectural patterns are transferable.

Specifically, I think the OpenACS community could benefit from:

  • A reference MCP server implementation for OpenACS (not just ]po[)
  • A standard pattern for wrapping ad_proc functions as agent tools
  • Shared thinking on how acs_permission and acs-workflow should interact with agent operations

This is the right conversation to be having, and ]po[ is better positioned for it than most people realize.


P.S.: Most of the above was researched and written by Claude Opus 4.5 given guidance and context from me. We got into a rabbit hole when talking about im_audit, as we did a full code analysis before writing the "Build audit logging" suggestion above.

Collapse
3: Re: API for AI Agents?!? (response to 2)
Posted by Frank Bergmann on
Hi Malte,

Yeah for non-English native speakers like us the AI stuff is a salvation.

However, it hallucinated im_timesheet::log_hours and a few other points, stressing that you just can't use it in a lot of places.

I take from that:
- A validation of my ideas concerning "read" operations (using indicators and a graph export of the database). Thanks! And yeah, that's probably where to start, because it's not that complicated and it's safe.
- A validation that permissions are a critical point. I'd want the agent to work with the permissions of the respective user only. Actually, I'm not sure how that could be implemented. I'll check.
- I like the idea of using workflow for human approval of agent work.
- A validation that im_audit is very, very important...

The idea of using the TCL API layer for "write" operations is interesting, but I think it wouldn't work precisely because of the permission issues. Access to the TCL API means superuser rights. Writing new TCL routines to be used specifically for the agent would be the same as writing new REST endpoints. In contrast, the existing ]po[ REST API already has permissions.

Iterate based on what agents actually do wrong

Iterate on what customers really need and what produces value for them. No idea about this at the moment...

Cheers!
Frank

Collapse
4: Re: API for AI Agents?!? (response to 3)
Posted by Malte Sussdorff on
Hi Frank,

On the Tcl API and permissions: we've actually been running a Tcl-based API layer in production with multiple clients for our SPA for several years now. We've extended the ]po[ namespace with additional wrapper procs for several modules — timesheet tracking, for example — specifically to give our SPA clean API entry points with validation and permission handling. The Tcl layer gives us access to the full business logic (validation, side effects, audit calls) that the REST endpoints sometimes bypass or duplicate. It handles permission checking at the application level before executing business logic, so it's not operating with superuser rights in practice. That said, I realize my response was written from the perspective of our extended codebase, which has additional features beyond the main ]po[ distribution. Your REST API approach with built-in permissions is a perfectly valid starting point, especially since it's already there and working.

The more interesting question is probably: regardless of which API layer you expose through MCP, how do you handle the permission delegation? You mentioned wanting agents to work with the respective user's permissions — that's exactly right, and it's where something like OAuth token scoping or a principal-user-id passed through the agent layer becomes important. The agent authenticates as itself but acts on behalf of a specific user, and the API layer enforces that user's permission set. We solved this in our Tcl layer but the same pattern would work on top of your REST API.

On the iteration point — absolutely, customer value first. What I meant is more pragmatic: once you have the read-only MCP server running, you'll quickly see which write operations users actually ask the agent to perform. That usage data tells you what to build next, rather than guessing upfront.

Cheers,
Malte