ADR-0023: Decompose core/agents into modules of at most 300 files¶
| Status | Accepted — implemented 2026-10-16. All six cuts are done (agents-jobs, agents-budget, agents-chatport, agents-browser, agents-interop, agents-studio, agents-tools, agents-turn); the kernel is at ~256 main files and the agents root package is empty. Still open: step 7 (removing the split packages) and the owed 32-user kind benchmark after the agents-tools/agents-turn cuts. Note (2026-10-21, v0.1.9): agents-turn has since grown to 307 main files, over the 300 cap, and the kernel to 259 (core module graph). |
| Date | 2026-10-16 |
| Deciders | Platform Engineering (maintainers) |
| Related | ADR-0011 Provider plugins, Structural audit 2026-10-14, Core module graph, ADR-AGENT-JOB-DURABILITY |
1. Problem¶
core/agents is the largest module in the reactor by a wide margin. On main at
a8476f547 it held 1165 main source files, with 154 classes in the root
package com.agenticai.core.agents. Every other module in core/ is under
310 files.
At that size the module costs us in four ways:
- Build and test time. Any change in
agentsrecompiles and retests about 4000 tests, and every module that depends onagents(app, app-jobs, app-worker, brief, mcpserver, omnichannel, platform, templates, voice, workflow) rebuilds. - No enforced direction inside it. The structural audit froze about 50
package-cycle violations under
com.agenticai.core.agents.*. Inside one Maven module nothing stops a new edge from closing another cycle. Between modules, Maven refuses a cycle at compile time. - The root package is a dumping ground. 154 classes with no shared concept
(the chat turn executor, the
Agententity, free-tier limits, response caches, edge telemetry, budget advisors) sit in one package, so package-private access couples all of them. - Ownership. Nobody can review "the agents module". People can review "the turn path" or "jobs".
2. Decision¶
- Rule: at most 300 main files per module, and an empty root package. The
root package
com.agenticai.core.agentsholds no classes once the decomposition is finished. A gate (section 6) ratchets both numbers down and never up. - Split by feature, in dependency order. Each new module depends on
agents(or on a lower split-out module).agentsnever depends on a module split out of it. Where code that stays inagentsneeds something from a split-out module,agentsowns a port (an interface, or a Spring event) and the split-out module implements it. - Keep Java package names on the first move. A class moves to a new Maven module with the same package. Split packages across jars work on the plain classpath that Spring Boot uses (we do not use JPMS), so no import changes outside the moved code, no change to Spring bean names, JPA entity names, REST paths, ArchUnit "area" names (they come from the package) or the frozen ArchUnit store. Renaming packages is a separate, later, mechanical step.
- Every app shape that loaded the code keeps loading it. A new module is
added to
core/pom.xml(module list and dependency management), toapp,app-jobsandapp-workerwhereagentsis listed, and to theCOPY <module>/pom.xmllist incore/Dockerfile(scripts/ci/dockerfile-poms.shenforces that).
3. Target module map¶
Counts are main source files as of this ADR. "Now" means after the
agents-jobs cut.
| Target module | Packages (under com.agenticai.core) |
Files | State |
|---|---|---|---|
agents-jobs |
agents.job and all sub-packages (schedule, trigger, progress, durability, ownership, approval, output, sentinel, operator, dto), agents.scheduledtask, agents.research, agents.tools.scheduling.ScheduleTaskToolCallback |
124 | Done (this ADR) |
agents-budget |
agents.spendcap, the per-user and per-run budget classes in the root package (PerUserBudget*, AgentRunBudget*, BudgetPolicy) |
~15 | In flight (parallel change) |
agents-chatport |
agents.chatport (chat export, import, transcripts) |
13 | In flight (parallel change) |
| vendor modules (ADR-0011) | google.agenttools, payments.agenttools, sarvam.agenttools, imagegen.agenttools, elevenlabs.agenttools move into their vendor modules, behind agentspi |
49 | In flight (ADR-0011 vendor extraction) |
agents-browser |
agents.tools.browseruse, agents.tools.web (web search, deep research tools) |
120 | Done (wave 2): 134 main files; Playwright left agents; ports tools.WebToolPort, tools.BrowserToolPort, capability.WebSearchAvailability |
agents-interop |
agents.a2a, agents.agui, agents.openai (compat endpoints), agents.collab, agents.crew, agents.directory |
52 | Done (wave 2): 50 files moved; ports A2aRemoteAgentToolSource, CollaboratorToolFactory, SpecialistHandoffService in agents; A2aProperties, A2aCardSigningService, RunBudget*, SwarmVerifierConfig, HandoffChain, HandoffStatus, SpecialistCandidate stay as shared vocabulary |
agents-studio |
agents.appbuilder, agents.coding, agents.importer, agents.demo, agents.lab, agents.loadtest, agents.experiment, agents.vision, agents.face, agents.skills, tutor, agents.ragquality |
~165 | Done: 100 main files; port tools.coding.CodingTaskToolFactory. experiment, vision, loadtest and skills went to agents-turn instead (the turn path uses them directly) |
agents-tools |
agents.tools root and the remaining agents.tools.* (classification, code, openapi, script, mcp*, search, messaging, device, x402, e2b, commerce, ...), tables |
~250 | Done (wave 2, section 5.2): 207 main files moved; ports tools.AgentToolPort, tools.ToolReplaySafety and the tools.ToolSearchToolNames constants in agents; the shared tool vocabulary (step events, tool-call log, journals, classification, trifecta enforcement, sandbox files and client, selection rules) and the ports other modules implement stay in agents |
agents-turn |
agents.turn (the turn path, with attachments, RL arms, HostedChainFailover, TenantScopedFlux, the turn journal endpoints and the chat SSE endpoint), agents.turn.quality, agents.turn.cache, agents.edge, agents.usermemory, agents.memory, agents.context, agents.hooks, agents.turnjournal, agents.resumable, agents.branching, agents.decision, agents.gateway, agents.assist, and (measured, section 5.3) agents.skills, agents.experiment, agents.vision, agents.loadtest, agents.share, agents.collab, agents.crew |
~260 | Done (wave 2, section 5.3): 283 main files moved plus the new AgentChatStreamController, 284 in all; agents-tools depends on it, not the other way round |
agents (kernel) |
agents.core (the Agent entity, settings, access, versioning, projection, prompt versions), agents.modality, agents.hosted (hosted-pool client FreeTier*/Hosted*), agents.quota, agents.guardrail, agents.runbudget, agents.dto, agents.version, agents.capability, agents.toolpolicy, agents.trust, agents.attestation, agents.consent, the shared tool vocabulary, the turn value types (TurnContext, ChatTurnRequest) and the ports the other modules implement (agentspi is its own module) |
~170 | Done (section 5.3): 255 main files, under the 300 cap; core/agents is no longer in the module-size baseline |
Dependency direction of the target:
agents (kernel, ports)
^-- agents-turn ^-- agents-tools ^-- agents-browser
^-- agents-turn ^-- agents-jobs, agents-chatport, agents-interop, agents-studio
agents-budget, agentspi (below agents)
As built (section 5.3) the edge between turn and tools points the other way
from the original plan: agents-tools depends on agents-turn. The class
graph showed no reference from the turn side into agents-tools (the turn
path already reached tools only through tools.AgentToolPort), while nine
tool classes referenced turn classes.
The two "Proposed" rows with the most risk are agents-tools and
agents-turn. Today AgentToolProvider needs Agent, and AgentChatService
needs AgentToolProvider (the reason tools was folded into agents in the
first place, see core/agents/pom.xml). With the entity in the kernel that edge
points the right way, but some tools call back into the turn (delegation,
a2a_call_agent, specialist hand-off). Those need ports in the kernel before
the move. A dependency scan of the actual class graph decides the final
boundary; the table is the plan, not a measurement.
4. How the agents-jobs cut was done¶
This is the pattern for the next cuts.
- Moved (packages unchanged): 122 main files and 74 test files. Two adapters and one paging test are new in
agents-jobs; three port interfaces are new inagents. The research facade moved with jobs, because a research run is an agent job (ResearchRunServiceis a thin layer overAgentJobService) and nothing outsideresearchreferenced it. - Stayed in
agentsas shared vocabulary or ports (split packages): job.AgentJobSession: how a job id becomes a chat session id. The turn path and three tools use it; it has no dependencies.job.progress.ProgressSource: the enum the progress port takes.job.schedule.ScheduledWorkflowRunner: already a port, implemented bycore/workflow. Keeping it inagentsmeansworkflowdoes not need a new dependency.- New ports in
agents, implemented inagents-jobs: job.AgentJobLookup(read-onlyJobFactssnapshot). Used by the approval replay backstop inAgentToolCallApprovalExecutorand bySkillDistillationService, which used to read theAgentJobentity and repository directly. Implemented byAgentJobLookupAdapter.job.progress.JobProgressRecorder. Used by the deep_research phase notes (ResearchToolWiring,AgentIntegrationToolResolver). Implemented byAgentJobProgressService.tools.scheduling.ScheduleTaskToolFactory. Used byAgentScheduledTaskToolResolver. Implemented byScheduleTaskToolCallbackFactory, which builds theschedule_tasktool exactly as the resolver did.- Wiring:
agents-jobsis in thecore/pom.xmlmodule list and dependency management, inapp,app-jobsandapp-worker, and in thecore/Dockerfilepom list. Thejson-schema-validatordependency moved with the structured-output code that imports it. - What did not change: bean names, entity names, tables, REST paths,
configuration keys, the class names listed in
application-shape-*.ymlscheduling roles, and the ArchUnit store.
agents went from 1165 to 1046 main files (122 out, 3 port interfaces in).
5. Sequencing¶
- Now, in parallel:
agents-jobs(done),agents-budget,agents-chatport, and the ADR-0011 vendoragenttoolsextraction. These are leaves with few inbound references, so they are the cheapest cuts. ADR-0011 goes first among the remaining work because it also removes five kernel-to-vendor Maven edges. - Gate (section 6), with today's numbers as the baseline.
agents-browser. Leaf; removes Playwright from every module that only needs agents.agents-interopandagents-studio. Mostly controllers and services with inbound references only from tests. Same pattern: move, invert the few references with ports.- Empty the root package, inside
agents. Move the 154 root classes into named packages (agents.core,agents.turn,agents.budget, ...) in one mechanical commit per target package, while no other change touchesagents. This is the only step that rewrites imports across modules. Update the frozen ArchUnit store entries by renaming, never by refreezing. Done 2026-10-16, see 5.1. agents-toolsandagents-turn. Introduce the kernel ports that break the tool-to-turn callbacks, then move. The turn path stays in-process (an extra jar is not a network hop, AGENTS.md rule 6), but run the 32-user kind benchmark after this step anyway: it changes Spring wiring on the hot path.agents-toolsdone 2026-10-16, see 5.2;agents-turndone 2026-10-16, see 5.3. The kind benchmark is still owed for both cuts.- Remove the split packages. Once a module is stable, move its ports into
a package the module owns in
agents(for exampleagents.jobport) and drop the shared package names.
5.1 Root package map (step 5)¶
All 163 classes of com.agenticai.core.agents (and their tests, which keep
their class's package) moved in one scripted commit; the root package is empty
in every module and the module-size baseline no longer lists it.
| Package | Side | Classes |
|---|---|---|
agents.core |
kernel | Agent, AgentConfigColumns, AgentRepository, AgentService and its collaborators (AgentAccessService, AgentCatalogOps, AgentCreationService, AgentSettings*, AgentModel*, AgentProjection*, AgentVersioningService, AgentSchema*, AgentToolAccessWriter, ...), AgentController, AgentSessionAccessGate, the entity value objects (CapabilityFlags, GenerationParams, FallbackPolicy, CachingPolicy, EdgeRoutingPolicy, ReasoningDepth, TuningMode, AgentTier, AgentAutonomyTier), GenerationParamsInferenceService, PromptVersion*, AgentPromptHistory, the eviction caches, HotpathLookupsConfig, the agent exceptions |
agents.modality |
kernel | ModelModalities*, ModalityModels, ChatAttachmentCategory, UnsupportedAttachmentTypeException (the entity and dto need them) |
agents.hosted |
kernel | FreeTierChatClientService, FreeTierTokenTrackingAdvisor, Hosted* except the stream failover (used by the kernel, tools, workflow and platform; no turn dependency) |
agents.quota |
kernel | FreeTierUsageLimiterService, FimCompletionEntitlementsAdapter, PlatformQuotaResetLog*, DailyQuotaResetScheduler |
agents.guardrail |
kernel | AgentGuardrailController, AgentGuardrailService, GuardrailNotAvailableForPlanException |
agents.runbudget |
kernel | AgentRunBudgetController, AgentRunBudgetService (not agents.budget: that package lives in the lower agents-budget module) |
agents.turn |
turn | AgentChatService, ChatTurn*, ChatPrompt*, BufferedTurn*, FastStream*, Chat*Facade, ChatServiceParts, TurnContext, ChatTurnRequest, LegacyChatEntryPoints, StreamEndWiring, TenantScopedFlux, HostedChainFailover, HostedFailoverPolicy, VerifierEscalationRouter, the attachment classes (ChatAttachment*, InlineAttachmentProcessor, PendingAttachments, attachment exceptions), the RL arm classes (Rl*, ChatArmConfig, ExperimentArmConfig), AgentChatSessionController, AgentChatStreamResponder, AgentLabCompletionService, AgentMessageEvents, AgentReliabilityService, TurnFeedbackAccessGate, TurnJournalController, TurnJournalService |
agents.turn.quality |
turn | LlmQualityJudgeService, AnswerConsistencyChecker, QueryComplexityClassifier, ReflexionService, TaskPlanningService |
agents.turn.cache |
turn | LlmResponseCacheService, SemanticResponseCacheService |
agents.edge |
turn | Edge* except EdgeRoutingPolicy (an entity value object) |
agents.usermemory |
turn | UserMemory* |
agents.memory, agents.decision |
turn | AgentMemoryController; AgentRelevanceSelector |
The attachment and RL-arm classes were not given their own packages: they
read AgentChatService's package-private fields and nested types, and a
split would have widened most of the turn path to public. The turn journal
endpoints stay in agents.turn because in agents.turnjournal they would
pull that acyclic package into the package cycle. Four successors of the
root package sit in the same package cycle the root package was in, so the
frozen store entry for the root package was renamed to agents.core,
agents.guardrail, agents.turn and agents.turn.quality.
Kernel-to-turn references left for step 6 (each needs a port in the kernel or a move):
agents.core.AgentControllerhosts the chat endpoints and buildsAgentChatStreamResponderoverAgentChatService.agents.share.AgentShareControllercallsAgentChatService#chat.agents.tools(AgentToolProvider,ToolResolverConfiguration,AgentCustomToolResolver,AgentCrewBrowserToolResolver) useAgentChatServiceandTurnContext. These moved toagents-toolsin 5.2, where they are legal for now (see the list there).
5.2 agents-tools cut (step 6, first half)¶
A scan of the class graph (jdeps over agents/target/classes) listed every
kernel or turn class that referenced a class under agents.tools.* or
tables. The cut keeps that set compiling without agents-tools:
- Ports in
agents, implemented inagents-tools: tools.AgentToolPort: every public instance method ofAgentToolProvider(the tool list for a turn, a delegated call or a specialist hand-off; tool candidates; the tools endpoint listing; the skills and procedures prompt blocks; the MCP cache eviction).AgentToolProviderimplements it and keeps its bean name. The turn path (AgentChatService,ChatServiceParts,ChatPromptAssembler,ChatDelegateCall,ChatSpecialistHandoff),AgentController,ToolAllowListCheck,EdgeToolExecutionController,TrifectaEnforcementService, AG-UI (agents-interop) and the demo studio (agents-studio) now depend on the port, so neither of those two modules needsagents-tools.tools.ToolReplaySafety:replaySafeVerdict, implemented byAgentToolGovernance, used byVerifierEscalationRouter.tools.ToolSearchToolNames: thesearch_tools/call_toolnames, whichSearchToolsToolCallback.NAMEandCallToolToolCallback.NAMEnow alias. The turn path and the hook runtime only compared tool names.- Stayed in
agents(shared tool vocabulary, split packages): step events (AgentStepEventEmitter,AgentStepEventPayloads,AgentStepEventRedactor), the tool-call log (ToolCallLog*,AgentToolCallStats),StepJournal*andEffectJournal, the wholetools.classificationpackage withTrifectaEnforcementService(the agent service enforces the trifecta on save),ToolDescriptor,ResolvedToolList,AgentToolSelectionwith what it wraps (NamespacedMcpToolCallback,SanitizedMcpToolCallback,McpToolArgumentGuard,McpToolOutputSanitizer,ToolRelevanceSelector,ToolRelevanceScoring),TenantContextPropagatingToolCallback(the characterisation harness uses it),e2b.SandboxFileRegistryand its helpers,code.ToolSandboxClientwith its DTOs (skills run scripts through it),context.RestoreToolResultToolCallback(context compaction), and the ports other modules implement:WebToolPort,BrowserToolPort,scheduling.ScheduleTaskToolFactory,coding.CodingTaskToolFactoryand the fivemessaging.*Portinterfaces (implemented inomnichannel, which therefore needs no new dependency). - Moved: 207 main files and 100 test files, packages unchanged. Bouncy
Castle moved with
tools.x402.agentswent from 742 to 535 main files by the module-size count.agents-browser,app,app-jobs,app-worker,briefandworkflowdepend onagents-tools;agents-studioandpaymentsonly in test scope.
References from agents-tools back into turn-side packages (legal while the
turn path is in agents; agents-turn will depend on agents-tools, so each
needs a kernel port or a move before that cut):
AgentToolProvidertakes aturn.TurnContext.ToolResolverConfiguration,AgentCustomToolResolverandAgentCrewBrowserToolResolvertakeObjectProvider<AgentChatService>.ToolSourceConfigurationusescontext.ChatContextCompaction.AgentToolGovernanceandAgentToolGuardusehooks.AgentToolHooks/AgentHookRuntime.AgentKnowledgeToolResolver,ToolResolverConfigurationandAgentToolCallApprovalExecutorusememory.AgentMemoryService,TenantMemoryService,SessionMemoryService,ChatTurnand the remember-fact tools.
5.3 agents-turn cut (step 6, second half)¶
A jdeps scan of agents/target/classes and agents-tools/target/classes gave
the boundary:
- No turn class referenced
agents-tools. The turn path reached tools only throughtools.AgentToolPort(section 5.2). - Nine
agents-toolsclasses referenced turn classes:AgentToolProvider(TurnContext),ToolResolverConfiguration,AgentCustomToolResolverandAgentCrewBrowserToolResolver(AgentChatService),ToolSourceConfiguration(ChatContextCompaction),AgentToolGovernanceandAgentToolGuard(hooks),AgentKnowledgeToolResolverandAgentToolCallApprovalExecutor(memory and the remember-fact tools).
So the cut makes agents-tools depend on agents-turn, not the reverse that
section 3 planned. That needs no new port; the planned direction would have
needed ports for the chat call, compaction, hooks and memory. The turn path
still never sees a tool implementation class, only the kernel port.
Moved to agents-turn (packages unchanged): 283 main files, 152 test files
and the built-in skill resources (src/main/resources/skills, same classpath
location):
- the turn-side packages of section 3:
turn,turn.quality,turn.cache,edge,usermemory,memory(withmemory.importer),context,hooks,turnjournal,resumable,branching,decision,gatewayandassist; skills,experiment,visionandloadtest, which phase A left inagentsbecause the turn path calls them directly;share(the public share chat callsAgentChatService; its vision endpoint callsvision);collabandcrewminus their vocabulary: theCollaboratorToolFactoryandSpecialistHandoffServiceports take anAgentChatService, so they sit with it.agents-interopimplements them, as before;core.AgentSessionAccessGate(it readsSessionMemoryService),tools.AgentToolSelection(it names the skill tools) andtools.context.RestoreToolResultToolCallback(it decodescontext.ToolResultRestoreIds).
Stayed in the kernel (split packages):
turn.TurnContextandturn.ChatTurnRequest, the turn's value types.AgentToolPorttakes aTurnContext, so the port can stay inagents.crew.HandoffChain,HandoffStatusandSpecialistCandidate(also inAgentToolPortsignatures), andcollab.RunBudgetandRunBudgetCaps(AgentRunBudgetServicereads them).- The MCP wrappers and relevance selector that
AgentToolSelectionuses.
The chat endpoint. AgentController (kernel) served POST
/api/agents/{agentId}/chat over AgentChatService. The endpoint moved to a
new controller, turn.AgentChatStreamController in agents-turn, with the
same path, body, headers and SSE format. This was the smaller change: a port
for "start a chat stream" would have needed the responder, resumable streams
and access checks behind it, while the endpoint is 30 lines.
- Its class-level mapping is the full path
/api/agents/{agentId}/chat, so it shares no base path with another controller and needs noentity-name-lintallowlist entry. OpenApiControllerAliasespublishes it asAgentController, so the operation keeps the idAgentController_chatand its SDK method.docs/api/openapi.jsonis unchanged.ChatBranchController(edit and regenerate) now delegates to it instead of toAgentController.AgentControllerkeepsSESSION_ID_HEADERandSTREAM_ERROR_MARKER.midStreamFailureMessageis gone from it; callers (AgentShareController,ChatFailedReply,ChatTurnDispatcher, A2A and AG-UI) callAgentChatStreamResponder.midStreamFailureMessage, where the logic already was.
Wiring. agents-turn is in the core/pom.xml module list and dependency
management, in app, app-jobs and app-worker, and in the core/Dockerfile
pom list. Modules that call the turn depend on it: agents-tools,
agents-chatport (session memory), agents-interop, agents-jobs,
agents-studio, brief (assist, experiments), mcpserver, omnichannel,
platform (session memory), templates (assist), voice and workflow.
quality needs nothing: its tests use their own AgentChatService stub.
What did not change: bean names, entity names, tables, REST paths,
configuration keys, application-shape-*.yml class names, the async-hop
allowlist and the frozen ArchUnit store. No class changed package and no
package was created.
5.4 Module map after step 6¶
Main and test .java files, counted 2026-10-16 after the agents-turn cut:
| Module | Main | Test | Depends on (agents family) |
|---|---|---|---|
agents (kernel) |
255 | 75 | agents-budget, agentspi |
agents-turn |
284 | 152 | agents |
agents-tools |
207 | 100 | agents, agents-turn |
agents-browser |
134 | 65 | agents, agents-tools |
agents-jobs |
132 | 76 | agents, agents-turn, agents-browser |
agents-studio |
100 | 47 | agents, agents-turn (agents-tools in test scope) |
agents-interop |
52 | 32 | agents, agents-turn, agents-budget |
agents-chatport |
21 | 9 | agents, agents-turn |
agentspi |
15 | 0 | none |
agents-budget |
11 | 3 | none |
Every module is under the 300 cap; core/agents left
scripts/ci/module-size-baseline.txt. Step 7 (dropping the split packages)
remains.
6. Enforcement¶
- Maven forbids the reverse edge:
agentshas no dependency on any module split out of it, so a reference back fails to compile. - Gate:
scripts/ci/check-module-size.sh(inmake gatesandstatic-gates.yml) counts main.javafiles percore/*module and classes directly incom.agenticai.core.agents, compared with the checked-in baselinescripts/ci/module-size-baseline.txtthat may only shrink (the same ratchet style and--updateflag as the file size check). Only entries over their limit are baselined (modules over 300, the root package over 0); a new module must stay at or below 300. - ArchUnit:
StructureRulesTestandModuleBoundaryRulesTestkeep working unchanged, because they import by package from the whole classpath. The frozen store can only shrink (AGENTS.md rule 13).
7. Consequences¶
- More modules in the reactor and more lines in each app shape's pom and the
Dockerfile.
dockerfile-poms.shcatches a forgotten Dockerfile line; a forgotten app-shape dependency shows up as a missing bean at boot, so runscripts/ci/boot-check.shafter each cut. - Split packages are a transitional state. They are invisible to Spring and to ArchUnit, but they would block a later move to JPMS until step 7 is done.
- Tests that exercised code in both halves moved to the higher module (for
example
SkillDistillationServiceTestandDeepResearchJobFlowTestnow run inagents-jobs), and keep their package so package-private access still works.
8. Addendum: omnichannel-social (2026-10-16)¶
core/omnichannel was the second module over the 300 main-file cap (308). The
Slack, Discord, Microsoft Teams and X adapters (71 main files, 14 tests) moved
to the new core/omnichannel-social, leaving omnichannel at 238 and removing
it from module-size-baseline.txt.
- Why this cut: the four packages (
slack,discord,teams,x) have no inbound references from the rest ofomnichannel, so no port interface or event was needed. They depend onomnichannel(sessions, dedup, triggers, theChannelTextSendand adapter contracts,metaforSlackCredential), never the reverse. Meta, Twilio, email, Telegram and WhatsApp voice stay: they reference each other (metaandtwilioandwhatsapp), so splitting them would need ports. - Unchanged: Java packages (
com.agenticai.core.omnichannel.{slack,discord,teams,x}), bean names, REST paths, entities, tables and config keys. Each package lives wholly in one module, so there are no split packages. - Wiring:
core/pom.xml,core/Dockerfileand theapp,app-jobsandapp-workerpoms. - Tests:
ChannelSendPortImplTestexercises every channel adapter, so it moved toomnichannel-socialand keeps its package.
8. Addendum: core/workflow split (333 to 280 main files)¶
core/workflow was over the 300-file module cap. Two cohesive parts left it,
both with unchanged Java packages, bean names, REST paths, tables and config keys:
- core/workflow-expression (package workflow.expression, 23 files): the
expression language. It has no reference to the rest of workflow, so it is a
leaf that workflow depends on (not the other way round, a deliberate
exception to "the new module depends on workflow": a leaf cannot create a
cycle and 9 workflow classes use it directly). Its tests and the golden
template fixtures moved with it; the web help test reads its sources from the
new path.
- core/workflow-portability (package workflow.portability, 30 files): DSL
export/import, Dify and n8n importers and their controllers. Nothing in
workflow references it, so it depends on workflow and workflow-expression
and is wired into app, app-jobs and app-worker. The agents-studio
edge (agent importer helpers) moved from workflow to this module.
Not cut: poll, share, diagram, version and humaninput are each
referenced from WorkflowController, WorkflowTriggerConfigService and similar
root classes, so moving them needs a port per package first.