einar-ioc

Best practices for building Go applications using Hexagonal Architecture and Einar-IoC

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "einar-ioc" with this command: npx skills add ignaciojeria/ioc-template/ignaciojeria-ioc-template-einar-ioc

Purpose

This skill is 100% oriented to vibe-coding: the agent scaffolds, wires, and modifies code by following these rules. Einar CLI is never used—the agent replicates its behavior manually. The Einar CLI equivalents and .einar.template.json are described only as reference so the agent understands how Einar CLI works and can produce equivalent output.

When to use

Use this skill whenever you are writing or modifying Go code that uses the github.com/Ignaciojeria/ioc library, or when you are creating APIs, event-driven components, or database adapters in a Hexagonal Architecture. When adding new components (controllers, repositories, consumers, etc.), apply the patterns from the rules—including adding blank imports to cmd/api/main.go—as if Einar CLI had scaffolded them.

[!TIP] Living Documentation: The rules in ./rules/ are generated from the actual .go files. Read the source code in app/adapter and app/shared as your primary reference—the rules reflect the template as it exists.

Quick reference

DomainRule files
Architecturearchitecture-guidelines, domain – domain by intention (entity, repository, client, service)
Einar CLI configeinar-template – template config for generators
Structure & mainstructure, main, archetype-version
Configurationconfiguration
HTTP / RESThttpserver, request-logger-middleware, fuegoapi-controllers
EventBuseventbus-strategy, eventbus-gcp, eventbus-nats, consumer, publisher
Use casesusecase, ports, architecture-guidelines
Databasepostgresql-connection, postgresql-migrations, postgres-repository
Observabilityobservability

Dependency Injection (IoC)

All components MUST be registered in the IoC container via var _ = ioc.Register(Constructor). See any rule file (e.g. httpserver, fuegoapi-controllers) for the exact pattern.

Blank imports are critical: Each package that registers constructors MUST be imported in cmd/api/main.go via a blank import (_ "archetype/path/to/package"). Without it, the package never loads and the IoC container will not receive those constructors. When adding a new component, the agent must add the corresponding blank import—the user does not do this manually.

Einar CLI equivalents (reference only—do not run the CLI)

The following section explains how Einar CLI works so the agent can replicate it. Never execute Einar CLI commands. When the user asks for something Einar CLI would do, scaffold the equivalent manually: use the rules as templates, apply the replacements, create modular files, and add the blank import to cmd/api/main.go.

New components not in the template: The user can request components not covered by the template (e.g. a new adapter type, a custom handler). The agent may create them freely but must follow the same structure and practices as the generator: one file per component, ioc.Register, constructor injection, blank import in main.go, and consistent naming (PascalCase for types, snake_case for files). For functions that are not candidates to be registered as singletons (helpers, pure functions, utilities), create them as you see fit—adjusted to the structure and following best practices.

How Einar CLI works (template + replace)

Einar CLI generates and renames .go files guided by .einar.template.json. That file defines, per generator: source_file (template), destination_dir, replace_holders (PascalCase/SnakeCase), and ioc_discovery (add blank import). The agent must:

  1. Take the template from the corresponding rule (e.g. fuegoapi-controllers for get.go).
  2. Create a new modular file (one file per operation/entity).
  3. Apply PascalCase/SnakeCase replacements: Template{OperationName}.
  4. Add the blank import to cmd/api/main.go (the agent does this; the user does nothing).

Replace holders by component (see einar-template for full config)

ComponentTemplate placeholderReplace with (PascalCase X = operation name)
get-controllerNewTemplateGetNew{X} (e.g. NewGetUser)
post/put/patch-controllerNewTemplatePost, TemplatePostRequest, TemplatePostResponseNew{X}, {X}Request, {X}Response
delete-controllerNewTemplateDeleteNew{X}
postgres-repositoryNewTemplateRepository, TemplateRepository, TemplateStructNew{X}Repository, {X}Repository, {X} (and template_table{x}_table)
pubsub-consumerNewTemplateConsumer, TemplateConsumer, TemplateMessage, template_topic_or_hookNew{X}Consumer, {X}Consumer, {X}Message, {x}_topic (SnakeCase)
publisherNewTemplatePublisher, TemplatePublisherNew{X}Publisher, {X}Publisher

Commands reference

User intent / Einar CLI commandTemplate ruleOutput (modular files)Blank import
einar install fuegohttpserver, request-logger-middlewareserver.go, request_logger.go_ "archetype/app/shared/infrastructure/httpserver", middleware
einar install postgresqlpostgresql-connection, postgresql-migrationsconnection.go, migrations/*.sql_ "archetype/app/shared/infrastructure/postgresql"
einar install gcp-pubsubeventbus-strategy, eventbus-gcpgcp_*.go_ "archetype/app/shared/infrastructure/eventbus"
einar generate get-controller Xfuegoapi-controllers (get.go)get_{x}.go in fuegoapi/_ "archetype/app/adapter/in/fuegoapi"
einar generate post-controller Xpost.gopost_{x}.gosame
einar generate postgres-repository Xpostgres-repository{x}_repository.go in postgres/_ "archetype/app/adapter/out/postgres"
einar generate pubsub-consumer Xconsumer{x}_consumer.go in eventbus/_ "archetype/app/adapter/in/eventbus"
einar generate publisher Xpublisher{x}_publisher.go in eventbus/_ "archetype/app/adapter/out/eventbus"

Constraints (from README)

  1. No init() for business components. Use ioc.Register at package level instead.
  2. No os.Getenv in logic. Inject configuration.Conf as a dependency.
  3. No ORMs with auto-migrations. Schema changes go in .sql files under app/shared/infrastructure/postgresql/migrations/. Use sqlx + golang-migrate.
  4. Don't extract variables for testability. Avoid var jsonMarshal = json.Marshal or injectable stubs just to reach 100% coverage. Prefer constructor injection; accept slightly lower coverage for unreachable error paths.

Architecture (see architecture-guidelines)

  1. No app/domain/port/ folder. Define interfaces at the same level as the implementation—in the consumer package (usecase) or next to the adapter.
  2. Always inject and return interfaces in IoC constructors. Each interface must have exactly one implementation registered; otherwise the IoC cannot resolve unambiguously.

Example: injecting a use case into a controller

The controller injects the input port (in.GetTemplateExecutor). The IoC resolves it from NewGetTemplateUseCase:

// Controller: inject ports/in executor
func NewGetTemplate(s *httpserver.Server, uc in.GetTemplateExecutor) {
	fuegofw.Get(s.Manager, "/templates/{id}",
		func(c fuegofw.ContextNoBody) (GetTemplateResponse, error) {
			out, err := uc.Execute(c.Context(), c.PathParam("id"))
			if err != nil {
				// handle error...
			}
			return GetTemplateResponse{ID: out.ID, Name: out.Name}, nil
		},
	)
}

The use case constructor returns (in.GetTemplateExecutor, error); the IoC stores that value and injects it into the controller.

Use case output: DTOs over domain entities

Prefer use case-specific DTOs (XxxInput, XxxOutput) over returning domain entities. Reasons:

  • Decoupling: The API contract stays independent of the domain model.
  • Explicit contracts: Each use case exposes only the fields it needs.
  • Agent-friendly: DTOs allow self-contained use case files with predictable patterns; agents can generate complete use cases without cross-package lookups.

Rules by domain

Architecture

  • architecture-guidelines – No ports folder, interfaces co-located, inject interfaces (one implementation per interface)

Einar CLI / generators

  • einar-template.einar.template.json: how Einar CLI generates and renames files

Structure and entry point

  • structure – Project directory tree (app/adapter, app/shared, cmd, scripts)
  • main – Entry point and ioc.LoadDependencies()
  • archetype-version – Embedded Version from .version file

Configuration

  • configuration – Environment config with caarlos0/env and godotenv

HTTP / REST (Fuego)

Use github.com/go-fuego/fuego for REST. Do not use net/http, gin, or fiber directly.

EventBus (CloudEvents, GCP / NATS)

Database (PostgreSQL)

Observability

  • observability – OpenTelemetry, slog injection, context propagation

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

Go Install

Install Go 1.22 compiler on Linux, configure environment variables, and provide commands for development, testing, building, and dependency management.

Registry SourceRecently Updated
1010Profile unavailable
General

Go 安装

在 Linux 系统安装并配置 Go 编译器,支持 Go 项目编译、测试及依赖管理操作。

Registry SourceRecently Updated
980Profile unavailable
General

Go Production Engineering

Expertise in Go project architecture, error handling, concurrency safety, testing, observability, configuration, CI/CD, and documentation for production depl...

Registry SourceRecently Updated
3090Profile unavailable
Coding

TickTick CLI (ttg)

Manage TickTick tasks and projects via the `ttg` CLI (github.com/dhruvkelawala/ticktick-go). Full CRUD, checklists/subtasks with progress display, reminders,...

Registry SourceRecently Updated
1230Profile unavailable