All chapters
  1. Start hereEnterprise AI adoption strategy, stage by stage and role by role
  2. Chapter 1Why AI adoption stalls
  3. Chapter 2Governance is the first enabler
  4. Chapter 3Who decides, who runs it
  5. Chapter 4Finding the right use cases
  6. Chapter 5The adoption ladder
  7. Chapter 6Role tracks
  8. Chapter 7Reuse first, as code
  9. Chapter 8The worked example
  10. Chapter 9The enablement program
  11. Chapter 10Measuring adoption honestly
  12. Chapter 11Evaluating and mapping tools
  13. Chapter 12Hands-on labs
  14. Chapter 13Templates, each filled
  15. Chapter 14Glossary
  16. AboutAbout this site
Chapter 7

Reuse first, as code

A governed asset catalog, advisory agent hooks, a reuse decision record, and CI checks that enforce it.

A shared library that nobody finds is not reuse. This chapter turns reuse first into a layered control: a governed asset catalog, an instructions file that sends the coding agent to it, an advisory agent hook, a recorded decision, and deterministic checks in the CI pipeline (continuous integration, the automated build and test run on every change) that enforce the result. Counts in this chapter are illustrative.

Local agent hooks are advisory. They nudge the coding agent and they can be skipped. Enforcement lives in the CI pipeline and in branch protection, which run whether or not anyone used an agent.

1. The problem · ten implementations of one idea

The organization had ten different date-and-time implementations (illustrative) across its services. A shared library, shared-datetime, already existed. Each implementation got the domain wrong in its own way, and three of them turned a contractual due date into a moment in time.

#Where it livesHow it handles the dateWhat went wrong
1Web appnew Date(dueDate) on a date-only stringThe string becomes midnight UTC (Coordinated Universal Time); every customer west of UTC, the West coast included, sees the day before
2notification-serviceStores the due date as a timestamp at 00:00 EasternReminders sent to Pacific customers name the wrong day
3statement-serviceConverts with a fixed -05:00 offsetWrong day for Pacific customers; ignores DST (daylight saving time) half the year
4Mobile appKeeps the date correct; shows the cutoff in the device zoneA travelling customer sees a cutoff with no zone label
5Marketing-email jobFormats the cutoff with the server's default zoneCustomers outside the data-center zone see the wrong cutoff time
6Contact-center desktopA copied, pinned old version of shared-datetimeMisses a later DST rule fix
7Autopay jobIts own business-day calculatorHoliday list hard-coded for one year
8Collections batchDays past due from the server clock dateIgnores the payment calendar
9Reporting jobTruncates payment instants to a date in UTCLate-evening Pacific payments land on the next day
10Dispute serviceA hand-written date parserAccepts invalid dates such as February 30
Why it happenedWhat it means
Not discoverableThe library had no catalog entry, so search found nothing and the developer wrote a helper
No contractThe library offered types but nobody said which type a due date must be
Agents accelerate itA coding agent writes a fresh helper in seconds; without context it will not look for the library
No enforcementNothing in the pipeline failed when a date-only field was parsed as an instant

The fix is not "use the library". The fix is a temporal-domain contract, owned by architecture and published in the catalog, that says what each kind of time value is.

2. The temporal-domain contract

The contract names four kinds of time value and one rule for each. The worked example in chapter 8 applies it end to end.

ConceptWhat it isType in shared-datetimeAuthoritative sourceRuleExample
Due dateA date-only value: a calendar date in the contractLocalDatepayment-schedule-serviceNever converted, never given a time or zone2026-11-16 everywhere, on every channel
CutoffAn instant: one moment, the same worldwideInstantpayment-schedule-service computes it (it owns the contractual business-calendar rule: 5:00 PM Eastern on the due date, illustrative fictional) and exposes it as an instantStored and passed as an instant in UTC; shared-datetime only formats it (formatPaymentCutoff), never computes it2026-11-16T22:00:00Z
Customer zoneAn IANA time zone (Internet Assigned Numbers Authority zone name)ZoneIdprofile-serviceA zone name, never a fixed offset; fallback labelledAmerica/Los_Angeles
DisplayText for a personformatInstant and formatDateEach channel, through the libraryFormat the instant in the customer zone; print the date as is"Due Nov 16 · pay by 2:00 PM PT" (PT = Pacific time)
Fallback zoneThe zone used when the profile has noneZoneId from a tableprofile-service policy table (product owns)Account's state of residence; the label says so"2:00 PM PT (based on your state of residence)"
Issued statementA recordSnapshot textstatement-serviceImmutable once issued; later zone changes apply to the next statementOctober statement keeps its printed cutoff
Never do thisWhy
Parse a date-only field into a date-timeIt invents a midnight and a zone that the contract never had
Store an offset such as -05:00 instead of a zone nameOffsets change with DST; zone names carry the rules
Format with the server or device default zoneThe customer's zone is data, not an environment setting
Re-render an issued statementA statement is a record under records management

3. The reference architecture · eight layers

Each layer catches something the others miss. No single layer proves that a duplicate does not exist.

LayerWho or what actsCatchesDoes not catchEnforcement point
1 · Asset catalogArchitecture owns it; asset owners keep entries currentLets anyone find shared-datetime, its version, status and limitsAn asset nobody registered; a stale entryNone; it is a source of truth
2 · Instructions fileThe coding agent reads it at session startTells the agent to query the catalog and which types to useAn agent session that ignores or truncates itNone; it is context
3 · Advisory checkAn agent hook or an MCP (Model Context Protocol) catalog tool, at plan time or before a new utility file is writtenKnown patterns: a new file named like a date helper, new Date( on a due dateDuplicates with new names; work done without an agentLocal, advisory, can be bypassed
4 · Decision recordThe developer records reuse, extend or create, with the reasonMakes the choice visible and reviewableA wrong reason that a reviewer acceptsReviewed in the pull request
5 · CI checksThe CI pipeline, on every pull requestBanned patterns, dependency policy, architecture rules, SBOM (software bill of materials) and licence, tests, decision record presentSemantic duplicates that match no ruleBlocking: the build fails
6 · Branch protectionThe repository platform; required reviewersMerging without passing checks or without an independent reviewerA reviewer who approves without readingBlocking: merge refused
7 · ExceptionsThe exception owner, with an expiryA justified new asset or a temporary bypass, kept visibleAn exception renewed foreverException register; the CI check reads it
8 · Catalog feedbackArchitecture and asset owners, monthlyFalse positives, missing assets, adoption, deprecationNothing on its own; it improves layers 1 to 5None; it feeds the others

4. Layer 1 · the catalog entry

A catalog entry is evidence, not marketing. The coding agent and the developer both read it, so it states limits as clearly as features.

Fieldshared-datetime
CapabilityDate-only values, instants, zone-aware formatting, business calendar
OwnerArchitecture, temporal working group; on-call rota published
Versions4.2 current; 3.x deprecated, end of support in two quarters (illustrative)
StatusSupported
Assurance levelReviewed by security; mutation-tested
Consumers7 teams / 31 repositories (illustrative)
LimitationsNo labelled cutoff formatter yet (formatPaymentCutoff proposed, display only); never computes a cutoff; zone data updated monthly; no historical calendars before 2015
ExamplesDue date display, cutoff display, statement snapshot, reminder text
ContractTemporal-domain contract v1, linked

5. Layer 2 · the instructions file

The instructions file is the team's standing context for the coding agent, reviewed like code. This excerpt is illustrative and vendor-neutral.

## Dates and times (temporal-domain contract v1)
- Before writing any date, time, zone or calendar helper, query the asset catalog
  for the capability "temporal". Prefer reuse; extend if close; create only with a
  decision record.
- Use shared-datetime 4.x. Never add another date library.
- A due date is a date-only value: LocalDate. Never parse it into a date-time.
- A cutoff is an Instant computed only by payment-schedule-service. Never compute it
  from the due date. Format it with formatPaymentCutoff(cutoffInstant, customerZone).
- The customer zone comes from profile-service as an IANA zone name. If missing,
  use the fallback table and show the fallback label.
- Issued statements are immutable. Do not re-render them.
- Record every reuse, extend or create choice in reuse-decision.yaml in the pull request.

6. Layer 3 · the advisory hook

An agent hook is a small program that the agent's runtime calls at a fixed event, such as just before the agent writes a file. This one fires when the agent is about to create something that looks like a new date utility. It returns candidates from the catalog with evidence; it never claims that reuse is certain.

Spec field"New date utility" advisory hook
EventBefore a file-write or file-create tool call by the coding agent
ScopeRepositories that consume customer-facing dates; paths under source folders; not tests or generated code
InputTarget path, proposed file content, repository name; no customer data
Trusted sourceThe asset catalog API (application programming interface), read-only, versioned
Output schemadecision (allow, advise), candidates (asset, version, capability, status, evidence), ask (record the choice)
Timeout3 seconds (illustrative)
Fail-open or closedFail-open with a warning: it is advisory, so a slow catalog never blocks work
Bypass authorityThe developer may proceed; the decision record and CI still apply
False-positive handlingThe developer marks it "not temporal" in one line; architecture reviews the marks monthly
Audit eventreuse.advisory.shown and reuse.advisory.dismissed, with repository, path and candidate
Enforcement pointNone here. Enforcement is layer 5 and layer 6

A generic configuration sketch (not any product's syntax):

hooks:
  - name: reuse-advisory-new-date-utility
    event: before_tool_call            # agent is about to write or create a file
    match:
      tools: [write_file, create_file]
      paths: ["src/**"]
      exclude: ["**/test/**", "**/generated/**"]
      content_regex: "new Date\\(|Date\\.parse\\(|setHours\\(|[+-]0[0-9]:00"
    run: catalog-check --capability temporal --stdin
    timeout_ms: 3000
    on_timeout: allow_with_warning     # fail-open: advisory only
    on_match: inject_context           # candidates go back to the agent
    audit_event: reuse.advisory.shown

What the hook returns to the agent:

{
  "decision": "advise",
  "candidates": [
    {
      "asset": "shared-datetime",
      "version": "4.2",
      "capability": "LocalDate due date; formatInstant for the source cutoff instant in customer zone",
      "status": "supported",
      "evidence": "catalog entry; temporal-domain contract v1; 7 teams / 31 repositories (illustrative)"
    }
  ],
  "ask": "Record reuse, extend or create in reuse-decision.yaml"
}
In Claude Code this is a PreToolUse hook in settings (Claude Code hooks); in GitHub Copilot CLI a preToolUse hook (GitHub Copilot hooks). Verify current docs before you build one; event names and payloads change.
The hook catchesThe hook does not catch
A new file named like a date helperA helper hidden inside a large file with an unrelated name
new Date( or a fixed offset in proposed codeCode written in an editor without the agent
An agent that skipped the instructions fileAn agent run where hooks are disabled locally
A missing decision record, by asking for oneA decision record with a poor reason

7. Layer 4 · the reuse decision record

The reuse decision record is a small machine-readable file in the pull request. The CI pipeline checks that it exists; the reviewer checks that its reason holds.

# reuse-decision.yaml
change: show contractual due date and payment cutoff consistently
capability: temporal
decision: extend                 # reuse | extend | create
asset: shared-datetime
version: "4.2"
reuse:
  - LocalDate for the due date (no conversion)
  - formatInstant(cutoff, customerZone) for the cutoff
extend:
  what: formatPaymentCutoff(cutoffInstant, customerZone), display only: formats the
        authoritative instant from payment-schedule-service with the zone label
        (or the labelled fallback zone); never calculates or overrides the cutoff
  why: three services recomputed the cutoff differently; payment-schedule-service alone
       computes it, and 4.2 has no labelled cutoff formatter
  owner_review: architecture temporal working group
create: none
alternatives_rejected:
  - local helper in notification-service (duplicates the rule)
contract: temporal-domain-contract v1
decided_by: developer
reviewed_by: architect     # not the author
date: 2026-10-29

8. Layers 5 and 6 · CI checks and branch protection

These layers fail closed. They run on every pull request, from any tool or none.

CheckFails the build whenOwner
Banned patternA date-only field is parsed as an instant, or a fixed offset appearsArchitecture
Dependency policyA second date library is addedArchitecture and security
Architecture ruleA channel or library computes a cutoff from the due date instead of displaying the payment-schedule-service instant with formatPaymentCutoffArchitecture
SBOM and licenceA new dependency has no SBOM entry or a licence outside policySecurity and legal
TestsThe temporal test matrix failsThe team
Decision recordA new file under a utility path arrives without reuse-decision.yamlThe team

A banned-pattern rule in a grep or semgrep style (illustrative):

rules:
  - id: date-only-parsed-as-instant
    languages: [typescript, javascript]
    severity: ERROR
    message: >
      dueDate is a date-only value. new Date() turns it into an instant at
      midnight and can show the wrong calendar day. Use LocalDate.parse from
      shared-datetime (temporal-domain contract v1).
    pattern-either:
      - pattern: new Date($X.dueDate)
      - pattern: new Date(dueDate)
      - pattern: Date.parse($X.dueDate)
  - id: fixed-utc-offset
    languages: [typescript, javascript, java]
    severity: ERROR
    message: Use an IANA zone name from profile-service, never a fixed offset.
    pattern-regex: '"[+-]0[0-9]:00"'

A decision-record check (illustrative):

# ci/check-reuse-record.sh: fail when a new utility file arrives without a record
new_utils=$(git diff --name-only --diff-filter=A origin/main...HEAD -- 'src/**/util*' 'src/**/*date*')
if [ -n "$new_utils" ] && [ ! -f reuse-decision.yaml ]; then
  echo "New utility files without reuse-decision.yaml:"; echo "$new_utils"
  exit 1
fi

Branch protection makes these checks required and adds a required reviewer who is not the author. When a coding agent opened the pull request, the person who asked the agent is the author for this rule.

9. Layers 7 and 8 · exceptions and catalog feedback

ItemExceptionCatalog feedback
Who raises itThe developer, with the asset ownerAnyone; the hook and CI log events automatically
Required fieldsOwner, reason, expiry, compensating controlKind (false positive, missing asset, stale entry), evidence
ExampleDispute service keeps its parser for one quarter (illustrative); compensating control: input validation testsThe hook flagged a test fixture 14 times in a month (illustrative); scope narrowed
What happens at expiryThe CI check reads the register; an expired exception fails the buildNot applicable
Reviewed byArchitecture; second line for customer-facing assetsArchitecture, monthly

10. The asset lifecycle

A reusable asset has a life: someone proposes it, someone assesses it, and someone retires it. Without the last step, the catalog fills with entries that agents still recommend.

StepWho actsOutputshared-datetime example
ProposeAny teamCatalog request with the capability and first consumerTemporal working group proposes the contract and library
AssessArchitecture, security, legalAssurance level, licence, owner, fundingSecurity review, licence check, owner named
PublishAsset ownerCatalog entry, examples, contract linkVersion 4.2 published with the contract
DiscoverDevelopers and coding agentsCatalog queries, hook candidatesThe hook returns it for a new date helper
Reuse or extendConsuming team, with the ownerDecision record; extension pull request to the assetformatPaymentCutoff (display only) added upstream, not copied
MonitorAsset ownerAdoption, defects, version spread, false positives3.x still in four repositories (illustrative)
DeprecateAsset owner, architectureEnd-of-support date; catalog status changes; CI warns, then fails3.x marked deprecated; the hook stops recommending it

Next: the worked example applies every layer to one ask. Copy-ready versions of the hook specification, the decision record and the catalog entry are in templates; Lab 3 in labs builds the hook and the CI check.