Welcome to the skills project! In this first chapter, we are going to look at the foundation of how features are added to our system. We call this the Command Registration Pattern.
Imagine you are building a digital assistant or a Command Line Interface (CLI). You want this assistant to have many capabilities, or "skills," like listing files, checking the weather, or processing text.
If you wrote all the code for every single skill in one giant file, your program would become messy, hard to read, and very slow to start up.
The Solution: We need a way to tell the system what skills exist without actually loading all the heavy code behind them immediately.
Think of this pattern like a menu in a restaurant:
In our project, the Command Registration Pattern is the menu. It describes the skill so the system knows it exists, but it leaves the "cooking" (loading the actual code) for later.
Let's look at a concrete example. We want to add a feature called skills that simply lists all the available commands in our system.
Instead of writing the logic right away, we first need to register it. We do this in a file called index.ts.
First, we need to make sure our registration follows the rules. We import a type called Command. This acts like a template or a form that ensures we don't forget important details like the name or description.
// index.ts
// We import the 'Command' type to ensure our object looks correct
import type { Command } from '../../commands.js'
Explanation: This line pulls in a blueprint. It tells TypeScript: "We are about to define a Command, so please check strictly if we make any mistakes."
Now, we define the "menu item." This object contains the metadata about our skill.
// Define the skill configuration
const skills = {
type: 'local-jsx',
name: 'skills',
description: 'List available skills',
// We will explain 'load' in the next chapter!
load: () => import('./skills.js'),
} satisfies Command
Explanation:
type: Tells the system what kind of output to expect (more on this in Local JSX Execution Interface).name: The keyword the user will type to use this feature.description: A helpful text that explains what this does.load: A function that points to where the real code lives.satisfies Command: This is our validation. If we forgot the name, this line would turn red and warn us.Finally, we export this object so the main system can find it.
// Make this configuration available to the rest of the app
export default skills
Explanation: By using export default, we allow the main application to "read the menu" by importing this file.
What happens when the application starts? It doesn't run the code inside skills.js yet. It simply scans these registration files to build a list of available commands.
Here is a simplified view of how the system reads your registration:
index.ts.name and description.load has not been touched yet.
While the code above is simple, the magic happens because of the Command interface. It enforces a strict structure. Here is a simplified version of what that interface looks like elsewhere in the project:
// Simplified definition of the Command interface
export interface Command {
name: string;
description: string;
type: string;
load: () => Promise<any>; // The instructions to fetch the code
}
Explanation: This interface is the contract. Because our skills object in index.ts uses satisfies Command, we guarantee that our plugin system will always know how to handle this feature.
In this chapter, we learned the Command Registration Pattern.
We defined the menu item, but we haven't discussed how the "meal" is cooked yet. You noticed the load property in our code:
load: () => import('./skills.js'),
How does this function work? How does it fetch the code only when needed? We will explore this in the next chapter.
Next Chapter: Lazy Module Loading
Generated by Code IQ