The Problem With One Command Doing Everything
You press Ctrl+Shift+A. A single input box appears. You type "move all contracts to legal folder." The system understands. You type "create a summary of Q4 performance." It works. You type "find documents modified in the last week and tag them urgent." Still works.
This shouldn't work. One command shouldn't handle 50+ completely different intentions—searching, creating, moving, summarizing, exporting, filtering, tagging, sharing, deleting. Each one requires different logic, different context, different outputs. Yet AiFiler's Universal Command does it without becoming an unmaintainable mess.
The trick isn't magic. It's architecture.
How We Structured Intent Recognition
When you open Universal Command (Ctrl+Shift+A), the system doesn't immediately try to guess what you want. Instead, it runs your input through intent heuristics—a layered classification system that lives in lib/intentHeuristics.ts.
The heuristics don't use a single neural network or complex ML model. They use pattern matching, keyword detection, and context awareness stacked in order of confidence.
Here's how the flow works:
User Input → Tokenize & Normalize → Keyword Matching → Context Analysis → Intent Classification → Route to Handler
The first layer is simple keyword detection. If your command contains "move" or "relocate" or "transfer," the system immediately flags it as a movement intent. If it contains "create" or "generate" or "write," it flags it as a creation intent. These keywords are grouped by semantic similarity, so the system catches variations without needing to hardcode every synonym.
The second layer is context. The system asks: What workspace am I in? What documents are currently selected? What was the last action I took? A command like "duplicate that" only makes sense if you've just selected a document. The context manager (in lib/intelligence/contextManager.tsx) tracks this state and passes it to the intent classifier.
The third layer is structural analysis. The system parses the command for objects and modifiers. "Move contracts to legal" has the structure [ACTION] [OBJECT] [DESTINATION]. "Tag all PDFs urgent and notify the team" has [ACTION] [FILTER] [OBJECT] [MODIFIER] [SECONDARY_ACTION]. These structures map to specific intent patterns.
If the heuristics can't reach high confidence (say, 85%+), the system escalates to a fallback: it asks the user to clarify. "Did you mean search for documents or create a new document?" This prevents silent failures.
The Intent Handler Architecture
Once the system classifies an intent, it routes to one of 87 intent handlers in lib/intelligence/intentHandlers.ts. Each handler is a pure function that takes context and parameters, and returns an action.
Here's a simplified example of what a handler looks like:
const moveDocumentHandler = async (context: IntentContext, params: {
documentIds: string[];
targetFolderId: string;
notify?: boolean;
}) => {
// Validate: do these documents exist? Do I have permission?
const validated = await validateDocumentAccess(params.documentIds);
// Execute: move them
const result = await moveDocuments(validated, params.targetFolderId);
// Side effects: update cache, log action, notify if requested
await updateLocalCache(result);
if (params.notify) {
await notifyCollaborators(result);
}
return {
success: true,
affectedCount: result.length,
message: `Moved ${result.length} documents`
};
};
Each handler is isolated. It doesn't know about the other 86 handlers. It doesn't care how it was called. It just knows: given these parameters and this context, do this thing. This isolation is critical. It means you can add a new handler without touching existing code. You can test it independently. You can rate-limit it independently.
The handlers are registered in a universal router (lib/intelligence/universalRouter.ts). The router is a map: intent type → handler function. When the classifier outputs an intent, the router looks up the handler and executes it.
const universalRouter = {
'move': moveDocumentHandler,
'search': searchHandler,
'create': createDocumentHandler,
'tag': tagDocumentHandler,
'export': exportDocumentHandler,
'summarize': summarizeHandler,
// ... 81 more handlers
};
This is a simple pattern—essentially a switch statement—but it's powerful because it's explicit and decoupled. Adding intent #51 means:
- Write the handler function
- Register it in the router
- Add a keyword pattern to the heuristics
- Done
You don't refactor existing code. You don't introduce new dependencies. You just extend.
Handling Ambiguity and Edge Cases
Real commands are messy. "Find contracts from last month" is clear. But "move old stuff" is ambiguous. Old how? Stuff where? The system has to decide: should it ask for clarification, or should it make a reasonable guess?
We built a confidence scoring system. Each heuristic layer outputs not just an intent, but a confidence score (0–100). If confidence is high (85+), execute immediately. If it's medium (60–85), ask for confirmation before executing. If it's low (<60), ask the user to rephrase.
For example:
- "Move contracts to legal" → 95% confidence (clear action, clear object, clear destination)
- "Move old stuff" → 45% confidence (action is clear, object and destination are vague)
- System response: "I found 340 documents matching 'old stuff.' Did you mean documents modified before [date]? And should I move them to a specific folder?"
This prevents the system from silently doing the wrong thing. It also trains users. Over time, they learn the phrasing that works best.
Why This Matters for Your Workflow
The Universal Command isn't just a search box. It's a command language for your documents. Because the handlers are isolated and the router is explicit, the system can do things that would be impossible in a traditional UI:
Chaining commands. You can string intents together: "Find all contracts from 2024, tag them reviewed, and move them to archive." The system parses this as three sequential intents, executes them in order, and reports the result.
Conditional logic. "If any documents are untagged, tag them pending-review and notify me." The system evaluates the condition, then executes the action only if true.
Batch operations at scale. Because handlers are stateless, they can be parallelized. Moving 500 documents doesn't require 500 sequential database calls. The system batches them.
Extensibility without bloat. You can add custom intents for your workflow. If your team always does "create a client brief and add it to the project folder," you can register that as a single intent instead of three separate commands.
The architecture also makes debugging easier. When something goes wrong, you know exactly which handler failed and why. You can test that handler in isolation. You can add logging to that handler without affecting others.
The Scalability Constraint
There's a real limit here, and we're honest about it. The system can handle 50–100 intents comfortably. Beyond that, the heuristics become harder to tune. Keyword collisions increase. Context becomes less useful. At some point, you hit diminishing returns.
We've designed the system so that if you hit that limit, the failure mode is graceful. Instead of the system guessing wrong, it asks for clarification. That's better than silent failure.
We've also built in monitoring. Every intent execution is logged with confidence scores, execution time, and success/failure. We can see which intents are being misclassified and adjust the heuristics.
What's Next
The current system is deterministic—it uses pattern matching and heuristics. We're exploring a hybrid approach where high-confidence intents use the existing system, and edge cases fall back to a lightweight language model for classification. This would push the limit higher without sacrificing speed or reliability.
But that's future work. Right now, the system works because we constrained the problem. We didn't try to build a general-purpose AI command parser. We built a system that handles the 50+ intents that matter for document management, and we made it so simple that you can understand exactly what's happening when you press Ctrl+Shift+A.
Enjoyed this article?
Get more articles like this delivered to your inbox. No spam, unsubscribe anytime.



