AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Kora Di Runtime

skill-kora-projects-kora-skills-kora-di-runtime · by kora-projects

Covers Kora runtime dependency-injection behavior - the Graph lifecycle, component init/release, disambiguation, collection injection, lazy/optional wrappers, and interception. Use when a component must start without being a dependency (@Root from ru.tinkoff.kora.common.annotation), when implementing init()/release() via Lifecycle or LifecycleWrapper, when disambiguating multiple beans of one int…

No reviews yet
0 installs
40 views
0.0% view→install

Install

$ agentstack add skill-kora-projects-kora-skills-kora-di-runtime

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-kora-projects-kora-skills-kora-di-runtime)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Kora Di Runtime? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Kora DI Runtime — Runtime Injection Behavior

Kora Version: 1.x Focus: Runtime DI — lifecycle, tags, collections, lazy dependencies, interception.

Read this first when:

  • Marking components as @Root for automatic startup
  • Implementing Lifecycle for init/release logic
  • Disambiguating with @Tag, collecting with All
  • Using ValueOf for lazy dependencies
  • Wrapping components with GraphInterceptor

References: See references/ for detailed guides on each topic.


Quick Start

@Root — Self-Starting Components

Only components that are dependencies of other components, or marked @Root (ru.tinkoff.kora.common.annotation.Root), are instantiated at runtime. @Root goes on a @Component class or on a @KoraApp/@Module factory method.

When to use @Root: HTTP/gRPC servers, Kafka consumers, cache warmers, schedulers, startup tasks — anything that must run even though nothing depends on it.

A self-starting worker:

import ru.tinkoff.kora.application.graph.Lifecycle;
import ru.tinkoff.kora.common.Component;
import ru.tinkoff.kora.common.annotation.Root;

@Root
@Component
public final class ServerRunner implements Lifecycle {
    private final ServerConfig config; // a @ConfigSource interface, injected as a component

    public ServerRunner(ServerConfig config) {
        this.config = config;
    }

    @Override
    public void init() throws Exception {
        System.out.println("Starting server on port " + config.port());
        // Bind socket, start accepting traffic
    }

    @Override
    public void release() throws Exception {
        System.out.println("Stopping server");
        // Stop server, release connections
    }
}

Config is supplied as a separate @ConfigSource component (see kora-config-hocon), never as a constructor-parameter annotation:

@ConfigSource("server")
public interface ServerConfig {
    int port();
}

Warning: Forget @Root and a non-dependency worker won't start — the application exits silently after the Graph is built.

> Learn more: [references/root-component-reference.md](references/root-component-reference.md) — Complete @Root guide with patterns and troubleshooting.


Component Lifecycle

Components with initialization/cleanup logic implement Lifecycle (ru.tinkoff.kora.application.graph.Lifecycle):

@Root
@Component
public final class DatabasePool implements Lifecycle {
    private final DataSource dataSource;
    private final ScheduledExecutorService scheduler;
    
    public DatabasePool(DataSource dataSource) {
        this.dataSource = dataSource;
        this.scheduler = Executors.newSingleThreadScheduledExecutor();
    }
    
    @Override
    public void init() throws Exception {
        try (Connection conn = dataSource.getConnection()) {
            System.out.println("Database connection OK");
        }
        scheduler.scheduleAtFixedRate(this::cleanup, 5, 5, TimeUnit.MINUTES);
    }
    
    @Override
    public void release() throws Exception {
        scheduler.shutdown();
        if (!scheduler.awaitTermination(30, TimeUnit.SECONDS)) {
            scheduler.shutdownNow();
        }
        if (dataSource instanceof AutoCloseable) {
            ((AutoCloseable) dataSource).close();
        }
    }
}

Key points:

  • init() is called after component creation, before use; release() during graceful shutdown (SIGTERM)
  • Release order is the reverse of init order
  • Components are initialized as parallel as the dependency Graph allows
  • For factory methods, wrap with LifecycleWrapper — see [Advanced DI Patterns](references/advanced-di-reference.md) for exact signature

Generic Factories

Generic methods in @Module interfaces become "generic factories" usable for ANY matching type. Use deliberately, or move helpers to top-level private static methods. See [Advanced DI Patterns](references/advanced-di-reference.md).

> Learn more: [references/lifecycle-reference.md](references/lifecycle-reference.md) — LifecycleWrapper, graceful shutdown, post-commit actions.


Tags and Collections

@Tag for Disambiguation

When multiple implementations of one interface exist, use @Tag (ru.tinkoff.kora.common.Tag) to select which one to inject. The tag is a marker class, not a string literal, so navigation and refactoring stay safe:

public final class RedisTag {}
public final class CaffeineTag {}

@Tag(RedisTag.class)
@Component
public final class RedisCache implements Cache {}

@Tag(CaffeineTag.class)
@Component
public final class CaffeineCache implements Cache {}

@Component
public final class UserService {
    private final Cache redisCache;
    private final Cache localCache;
    
    public UserService(
        @Tag(RedisTag.class) Cache redisCache,
        @Tag(CaffeineTag.class) Cache localCache
    ) {
        this.redisCache = redisCache;
        this.localCache = localCache;
    }
}

All for Collections

Inject every untagged implementation of a type. All (ru.tinkoff.kora.application.graph.All) extends List:

import ru.tinkoff.kora.application.graph.All;

@Component
public final class NotificationService {
    private final List notifiers;

    public NotificationService(All notifiers) {
        this.notifiers = List.copyOf(notifiers);
    }

    public void notify(String message) {
        notifiers.forEach(n -> n.send(message));
    }
}

To collect every implementation including tagged ones, request @Tag(Tag.Any.class):

public NotificationService(@Tag(Tag.Any.class) All notifiers) { ... }

@Tag(SomeTag.class) All collects only the components registered under SomeTag.

> Learn more: > - [references/tag-injection-reference.md](references/tag-injection-reference.md) — @Tag patterns > - [references/collection-injection-reference.md](references/collection-injection-reference.md) — All, Tag.Any patterns


ValueOf — Lazy Dependencies

ValueOf (ru.tinkoff.kora.application.graph.ValueOf) provides lazy access via get() and decouples lifecycles: depending on ValueOf tells the Graph that this component is NOT refreshed when B changes. ValueOf also exposes refresh().

import ru.tinkoff.kora.application.graph.ValueOf;

@Component
public final class ApiClient {
    private final ValueOf config;

    public ApiClient(ValueOf config) {
        this.config = config;
    }

    public Response get(String url) {
        var currentConfig = config.get(); // always the latest instance
        // ApiClient is NOT recreated when AuthConfig refreshes
        return doGet(url, currentConfig);
    }
}

Use cases: breaking refresh cascades, breaking circular dependencies, lazy access to a component that may not be ready at construction.

Optional dependencies use a @Nullable constructor parameter (any @Nullable: jakarta.annotation.Nullable, javax.annotation.Nullable, or org.jetbrains.annotations.Nullable); the Graph then tolerates the absence of that component instead of failing the build.

> Learn more: [references/optional-dependency-reference.md](references/optional-dependency-reference.md) — @Nullable and ValueOf patterns.


GraphInterceptor — Component Wrapping

GraphInterceptor (ru.tinkoff.kora.application.graph.GraphInterceptor) wraps or modifies a component during graph construction. Its contract mirrors Lifecycle except init/release return the (possibly replaced) instance that other components will then receive:

@Component
public final class MetricsInterceptor implements GraphInterceptor {
    private final MeterRegistry meterRegistry;
    
    public MetricsInterceptor(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    @Override
    public HttpClient init(HttpClient client) {
        return new MetricsHttpClient(client, meterRegistry);
    }
    
    @Override
    public HttpClient release(HttpClient client) {
        return client;
    }
}

Use cases: Metrics, tracing, circuit breakers, logging proxies.

> Learn more: [references/graph-interceptor-reference.md](references/graph-interceptor-reference.md) — Complete interceptor patterns.


Common Pitfalls

| Problem | Solution | |---------|----------| | HTTP/GRPC server doesn't start | Mark server component with @Root | | Kafka consumer not polling | Mark consumer with @Root | | Component silently not created | Check it's used by @Root or marked @Root itself | | Component restarted on config change | Use ValueOf for lazy dependency | | Ambiguous dependency error | Use @Tag to disambiguate | | LifecycleWrapper factory returns wrong type | Return Wrapped, use constructor (see [Advanced DI](references/advanced-di-reference.md)) | | Generic method in @Module causes implicit bindings | Move helpers to top-level private static methods (see [Advanced DI](references/advanced-di-reference.md)) |


Checklist

- [ ] Component marked @Root if it must start automatically?
- [ ] Implements Lifecycle for init/release logic?
- [ ] Resources properly released in release()?
- [ ] Using @Tag to disambiguate multiple implementations?
- [ ] Using All for untagged collections, @Tag(Tag.Any.class) List for all components?
- [ ] Using ValueOf for lazy dependencies?
- [ ] Using GraphInterceptor for component wrapping?

Assets

Templates in assets/: Application, RootComponent, LifecycleComponent, LifecycleFactory, TaggedComponent, CollectionComponent, GraphInterceptor, ValueOfComponent, build configs.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.