npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@synet/unit

v1.1.1

Published

Unit of Unit Architecture

Readme

(⊚) Unit Architecture

   _    _       _ _                            
 | |  | |     (_) |                           
 | |  | |_ __  _| |_                          
 | |  | | '_ \| | __|                         
 | |__| | | | | | |_  _     _ _            _  
  \____/\_| |_|_|\__|| |   (_) |          | |   
      /  \   _ __ ___| |__  _| |_ ___  ___| |_ _   _ _ __ ___ 
     / /\ \ | '__/ __| '_ \| | __/ _ \/ __| __| | | | '__/ _ \
    / ____ \| | | (__| | | | | ||  __/ (__| |_| |_| | | |  __/
   /_/    \_\_|  \___|_| |_|_|\__\___|\___|\__|\__,_|_|  \___|


version: 1.1.1
                                                              

Here's something I've been thinking about: what if your code could actually learn from other code? Not through inheritance, dependency or injection, but by literally teaching and learning capabilities ?

const myService = EmailService.create();
myService.learn([crypto.teach()]); // Now it can sign emails
myService.learn([storage.teach()]); // Now it can save drafts

// That's it. Your email service just learned cryptography and storage.

I know it sounds weird, but stick with me. This isn't another framework trying to solve everything. It's a pattern that makes software composition feel... natural.

What you get:

  • Code that can teach and learn new things, without dependencies
  • AI-ready components (every unit works with AI tools automatically)
  • Loose coupling that doesn't hurt
  • Systems that evolve without breaking

The Basic Idea

Every Unit can do two things:

  1. Teach - share what it knows with other units
  2. Learn - acquire new capabilities from other units
// Create some units
const crypto = CryptoUnit.create();
const emailer = EmailUnit.create();

// Email unit learns crypto capabilities
emailer.learn([crypto.teach()]);

// Now email can do crypto stuff
const signed = await emailer.execute('crypto.sign', message);

That's really it. No complex wiring, no dependency graphs to manage. Units just teach each other what they know.

A Real Example

Let's say you're building a notification system. You need to send emails, encrypt sensitive data, and maybe store some logs. Here's how we got used to approach it:

// The usual way - inject everything you might need
class NotificationService {
  constructor(
    private emailer: EmailProvider,
    private crypto: CryptoService,
    private logger: Logger,
    private storage: Storage
  ) {}
  
  async sendSecureNotification(user: User, message: string) {
    // Hope all the dependencies work together...
  }
}

It's clean, it works, but you're now coupled to specific implementations, testing is a pain because you have to mock everything, and adding new capabilities means updating constructors everywhere. When it get out of control - CommandBuses, Mediators, Queries - massive cognitive, that becomes unmanagable.

Here's the Unit way:

// Create a unit that starts simple
const notifier = NotificationUnit.create();

// Teach it what it needs to know, when it needs to know it
notifier.learn([
  emailUnit.teach(),    // Now it can send emails
  cryptoUnit.teach(),   // Now it can encrypt
  loggerUnit.teach()    // Now it can log
]);

// Use the capabilities it learned
await notifier.execute('email.send', user, message);
await notifier.execute('crypto.encrypt', sensitiveData);

Why This Matters

Testing gets easier. Instead of mocking a dozen dependencies, you test units in isolation and then test the learning contracts.

AI integration is automatic. Every unit exposes its capabilities as schemas that AI tools can understand and use immediately.

Your architecture stays flexible. Need to swap email providers? Teach your units a different email capability. The rest of your code doesn't change.

New team members get productive faster. They can ask any unit "what can you do?" and get a real answer.

How Units Work

A Unit is just a class, a Value-Object, that follows a specific pattern:


// Implementation - your Unit
class EmailUnit extends Unit<Props> {
  // 1. Every unit has a protected constructor
  protected constructor(props:Props) {
    super(props);
  }
  
  // 2. Create through static factory
  static create(config:Config) {
    return new EmailUnit({
      dna: { id: 'email', version: '1.0.0', description: 'my first unit' },
      apiKey: config.apiKey // Immutable props
    });
  }
  
  // 3. Define what you can teach others
  teach() {
    return {
      unitId: this.dna.id,
      capabilities: {
        'send': (...args) => this.sendEmail(...args),
        'template': (...args) => this.renderTemplate(...args)
      },
      schema: {
        send: { /* describes the send method for AI */ },
        template: { /* describes the template method for AI */ }
      }
    };
  }
  
  // 4. Your actual business logic
  private async sendEmail(to: string, subject: string, body: string) {
    // Send the email however you want
  }
}

That's it. Once you have units, they can teach and learn from each other.

Getting Started

Install the package:

npm install @synet/unit

Create your first unit:

import { Unit } from '@synet/unit';

class MathUnit extends Unit {
  protected constructor(props) { super(props); }
  
  static create() {
    return new MathUnit({
      dna: { id: 'math', version: '1.0.0' }
    });
  }

  build() {

     // Unit methods as capabilities    
     Capabilities.create(
      unitId: this.props.dna.id,
      {
        'add': (a, b) => a + b,
        'multiply': (a, b) => a * b
     });

    // Schema and AI tool 
    Schema.create(
      unitId: this.props.dna.id,
      {
        add: {
          description: 'Add two numbers',
          parameters: { a: 'number', b: 'number' }
        }
      })
    
    // Schema and capabilities are validated on build.     
    const validator = Validator.create({
      unitId: this.props.dna.id,
      capabilities,
      schema,
      strictMode: false
    });

    return { capabilities, schema, validator };
  }
  
  // Teach any unit your capabilities, schemas and provide own validation logic
  teach(): TeachingContract {
    return {
      unitId: this.props.dna.id,
      capabilities: this._unit.capabilities,
      schema: this._unit.schema,
      validator: this._unit.validator
    };
  }
}
// Use it
const math = MathUnit.create();
const calculator = CalculatorUnit.create();

calculator.learn([math.teach()]);
const result = calculator.execute('math.add', 5, 3); // 8

AI Integration

This is where it gets interesting. Every unit automatically works with AI:

import { chatWithTools } from '@synet/ai';

// Your units become AI tools automatically
const weather = WeatherUnit.create({ apiKey: 'your-key' });
const email = EmailUnit.create({ apiKey: 'your-key' });

// AI can use them directly
const response = await chatWithTools([
  weather.teach(), 
  email.teach()
], "Check the weather in NYC and email me the forecast");

// The AI will:
// 1. Call weather.getCurrentWeather('NYC')  
// 2. Call email.send('[email protected]', 'Weather Forecast', result)

No tool definitions to write, no schema mapping, no integration code. Units handle all of that for you.

Testing

Testing units is straightforward because they're self-contained:

describe('EmailUnit', () => {
  it('should send emails', async () => {
    const email = EmailUnit.create({ apiKey: 'test-key' });
    const result = await email.execute('send', '[email protected]', 'Subject', 'Body');
    expect(result.success).toBe(true);
  });
  
  it('should teach email capabilities', () => {
    const email = EmailUnit.create({ apiKey: 'test-key' });
    const contract = email.teach();
    
    expect(contract.capabilities).toHaveProperty('send');
    expect(contract.schema.send).toBeDefined();
  });
});

Test learning between units:

it('should learn and use capabilities', () => {
  const crypto = CryptoUnit.create();
  const email = EmailUnit.create({ apiKey: 'test-key' });
  
  email.learn([crypto.teach()]);
  
  expect(email.can('crypto.sign')).toBe(true);
  expect(email.can('crypto.encrypt')).toBe(true);
});

Events and Observability

Units have built-in event support for monitoring and debugging:

const email = EmailUnit.create({ apiKey: 'your-key' });

// Listen to what your units are doing
email.on('email.send', (event) => {
  console.log(`${event.unitId} executed ${event.capability} in ${event.duration}ms`);
});

// get all events 
email.on('*', (event) => {
  console.log(`${event.type} emitted`);
  if(event.error) {
      console.log(`${event.type} error: ${event.error.message}`);
  }  
});


// Use wildcards to all or certain event types, like unit.*, *.error etc.
email.on('email.*', (event) => {
  console.log(`${event.unitId} executed ${event.capability} in ${event.duration}ms`);
});


email.on('error', (event) => {
  console.log(`Error in ${event.unitId}: ${event.error.message}`);
});

// Events are emitted automatically
await email.execute('send', '[email protected]', 'Hello', 'World');
// → capability.executed event fired

You can disable events for performance in high-volume scenarios:

const email = EmailUnit.create({ 
  apiKey: 'your-key',
  emitEvents: false  // Skip events for better performance
});

Why this rocks

You stop writing glue code. Units figure out how to work together.

Testing becomes simple. Test units in isolation, then test the learning contracts.

AI integration is free. Every unit works with AI tools automatically.

Self-documenting Just call unit.help() and get full documentation and available methods. Always up-to-date, close to the source, changed together.

Your architecture stays flexible. Need to change providers? Teach your units new capabilities. The rest of your code doesn't change.

Common Patterns

Here are some patterns that teams find useful:

// Capability composition
const api = ApiUnit.create();
api.learn([
  auth.teach(),        // Authentication
  logger.teach(),      // Logging
  metrics.teach(),     // Monitoring
  cache.teach()        // Caching
]);

// Feature units
const userService = UserServiceUnit.create();
userService.learn([
  database.teach(),    // Data persistence
  email.teach(),       // Notifications
  crypto.teach()       // Password hashing
]);

// AI-powered workflows
const assistant = AssistantUnit.create();
assistant.learn([
  userService.teach(), // User management
  api.teach(),         // External APIs
  scheduler.teach()    // Task scheduling
  cryptoUnit.teach(),    // Encryption  
]);

Getting Help

Every unit documents itself:

// Ask any unit what it can do
console.log(myUnit.help());

// Check if it has specific capabilities
if (myUnit.can('crypto.sign')) {
  await myUnit.execute('crypto.sign', data);
}

// See what it's learned
console.log(myUnit.capabilities().list());

The documentation is always up-to-date because it's generated from the actual running code.

Enterprise Adoption

While Unit Architecture started as a developer productivity pattern, many teams are finding it valuable for enterprise-scale applications:

Benefits for teams :

  • Faster integration between teams (no more "integration meetings")
  • Better AI tooling adoption (every component works with AI immediately)
  • Easier testing and maintenance (units are self-contained)
  • Reduced vendor lock-in (swap implementations by teaching new capabilities)
  • Less type-battles. Schemas allow validation.

Common enterprise patterns:

// Multi-provider support
const storage = StorageUnit.create();
storage.learn([
  awsS3.teach(),     // Primary storage
  azureBlob.teach(), // Backup storage
  gcs.teach()        // Archive storage
]);

// Compliance and audit trails
const processor = ProcessorUnit.create();
processor.learn([
  auditLogger.teach(),    // Track all operations
  encryptionUnit.teach(), // Encrypt sensitive data
  validatorUnit.teach()   // Ensure data quality
]);

If you're evaluating Unit Architecture for enterprise use, the DOCTRINE.md file contains the complete architectural principles and patterns.


Questions? Issues? Ideas?
Technical documentation | GitHub Issues | Documentation | Examples Email me