Back to Internal Knowledge Base Management

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

Developer Handover Pack

Internal Knowledge Base Management

[YourCompany.com] · Operations Department · Prepared by FullSpec · [Today's Date]

This document gives the FullSpec build team everything needed to configure, connect, and deploy the two-agent automation that replaces the manual knowledge base management process. It covers the current-state step map with bottleneck flags, full agent specifications with IO contracts, an end-to-end data flow trace, and the recommended build stack. You, as the process owner, are responsible for providing Notion API access, confirming article ownership categories, and being available during the testing window described in Section 02.

01Process snapshot

Step
Name
Description
1
Receive New Content or Update Request
Staff member submits a request via Slack or email; the operations manager manually reads and logs each one. Time cost: 10 min/cycle.
2
Assess and Prioritise Request
The operations manager decides whether the request is valid, urgent, or a duplicate. Assessment is informal and inconsistent. Time cost: 15 min/cycle. BOTTLENECK.
3
Assign Article Owner
An appropriate subject-matter expert is identified and manually messaged via Slack. No formal handoff record is created. Time cost: 10 min/cycle.
4
Draft or Update Article Content
Assigned owner writes or edits in Google Docs or Notion. Loom recordings sometimes attached. Time cost: 45 min/cycle.
5
Notify Reviewer and Request Approval
Author manually messages the reviewer via Slack or email. No structured approval workflow; follow-up is left to the author. Time cost: 10 min/cycle. BOTTLENECK.
6
Review Draft for Accuracy
Reviewer reads the draft, leaves inline comments in Google Docs, and approves or returns it. Time cost: 20 min/cycle.
7
Incorporate Reviewer Feedback
Author addresses comments and revises. Can repeat two or three times before finalisation. Time cost: 20 min/cycle.
8
Publish Article to Knowledge Base
Approved content manually copied and formatted into Notion by the operations manager; metadata filled in by hand. Time cost: 20 min/cycle.
9
Announce New or Updated Article
Operations manager posts a manual Slack message to the team. Coverage is inconsistent. Time cost: 5 min/cycle.
10
Track Review Due Dates
Operations manager maintains a spreadsheet of review dates and manually chases owners when dates pass. Time cost: 15 min/cycle. BOTTLENECK.
11
Chase Overdue Reviews
Individual Slack reminders sent for overdue articles. Many articles are never chased and remain stale. Time cost: 15 min/cycle.
12
Archive or Retire Outdated Articles
Old article manually moved to archive or deleted once replacement is live. Step is frequently skipped. Time cost: 10 min/cycle.
Time cost summary: Total manual time per cycle is 195 minutes (3 hrs 15 min). At approximately 30 article cycles per month the process consumes roughly 97.5 hours/month, benchmarked against the observed steady-state load of 5 manual hours/week (300 min/week). Steps 2, 3, 5, 8, 9, 10, and 11 are replaced by the two agents. Steps 1 (intake channel), 4 (drafting), 6 (review), and 7 (revision) remain human-owned.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Knowledge Triage Agent

Reads each incoming Google Forms submission, queries the Notion knowledge base for existing articles with overlapping titles, tags, or keyword matches, and classifies the request as new, update, or duplicate. It scores urgency based on subject-area flags in the form, assigns a priority tier (P1 critical, P2 standard, P3 low), and selects an owner from a pre-built reference table keyed to content categories. The output is a structured record ready to be written as a new Notion database page. This agent removes the need for the operations manager to manually assess and triage every submission, which currently takes 15 minutes of informal judgement per request and produces inconsistent results.

Trigger
New Google Forms response received (webhook or polling interval of 5 minutes via the automation platform).
Tools
Google Forms, Notion (database query and page creation), Google Docs (template clone for draft scaffold).
Replaces steps
Steps 2 and 3: Assess and Prioritise Request; Assign Article Owner.
Estimated build
12 hours. Complexity: Moderate.
// Input
form_response_id: string          // Google Forms response ID
submitter_email: string           // respondent email address
request_type: enum               // 'new_article' | 'update_existing' | 'flag_incorrect'
article_title_hint: string        // free-text title or description from form
urgency_flag: boolean            // checkbox on form
subject_area: string             // dropdown selection from form

// Processing (internal)
notion_query_results: array      // existing pages with title similarity score >= 0.7
duplicate_detected: boolean      // true if any result score >= 0.85
assigned_owner_id: string        // looked up from ownership reference table by subject_area
priority_tier: enum             // 'P1' | 'P2' | 'P3'
classification: enum            // 'new' | 'update' | 'duplicate'

// Output
notion_task_page_id: string      // ID of newly created Notion article task page
notion_task_url: string          // direct link to the Notion page
assigned_owner_slack_id: string  // Slack user ID for downstream notification
duplicate_flag: boolean          // passed to decision branch in orchestration layer
priority_tier: enum             // carried forward for routing logic
  • Notion API access requires a paid Notion plan (Plus or above). Confirm the workspace plan before starting the build. If the free tier is in use, substitute Airtable or Google Sheets as the task database and adjust all Notion nodes accordingly.
  • The ownership reference table must be built and populated before this agent can auto-assign. Allow two to three hours with the operations manager to define subject-area categories and map each to a Slack user ID and Notion user ID.
  • Duplicate detection uses Notion full-text search against the 'Name' and 'Tags' properties. A similarity threshold of 0.85 triggers the duplicate branch; results between 0.70 and 0.84 are flagged as 'possible overlap' and included in the Notion task for the operations manager's awareness but do not block creation.
  • If no matching owner is found in the reference table for the submitted subject_area, the task is created with owner set to 'Unassigned' and a Slack alert is sent to the operations manager. Do not let the workflow fail silently on a missing owner.
  • The Google Docs template clone (draft scaffold) requires a specific template file ID to be stored in the automation platform's credential store. Confirm this file ID during configuration and pin it; do not rely on a dynamic lookup.
  • Deduplication: if duplicate_detected is true, the orchestration layer routes to an exception branch where the operations manager is alerted via Slack with both the new submission and the matching existing article link. The agent does not create a new Notion page in this branch.
  • Confirm that the Google Forms webhook or polling interval is consistent with the expected submission volume of approximately 30 requests per month. A five-minute polling interval is acceptable; a webhook is preferred for latency.
Review and Publish Coordinator Agent

Monitors the status field of every article task page in Notion and fires the correct downstream action whenever a status transition occurs. When a task moves to 'Ready for Review', it routes the draft to the designated reviewer via Slack with a direct link. When the reviewer records their decision in Notion (Approved or Changes Required), it either triggers publication and announcement or notifies the author to revise. On approval, it updates the Notion page status to 'Published', writes the publication date and next review date to the page properties, and posts a formatted announcement to the designated Slack channel. It also runs a daily scheduled check for articles within seven days of their review date and sends Slack reminders to the assigned owner. This agent replaces steps 5, 8, 9, 10, and 11, and the archiving prompt in step 12.

Trigger
Notion database page property change: 'Status' transitions to 'Ready for Review', 'Approved', 'Changes Required', or 'Review Due'. Secondary trigger: daily scheduled run at 08:00 local time to check 'Next Review Date' values.
Tools
Notion (status watch, property write, database query), Slack (direct messages and channel posts), Google Docs (draft link extraction from Notion page property).
Replaces steps
Steps 5, 8, 9, 10, and 11: Notify Reviewer and Request Approval; Publish Article to Knowledge Base; Announce New or Updated Article; Track Review Due Dates; Chase Overdue Reviews. Also triggers the archive prompt in step 12.
Estimated build
16 hours. Complexity: Moderate.
// Input (status-change branch)
notion_page_id: string           // triggering article task page ID
notion_page_url: string          // direct page link
article_title: string            // Notion 'Name' property
new_status: enum                // 'Ready for Review' | 'Approved' | 'Changes Required'
assigned_reviewer_notion_id: string  // Notion user ID of reviewer
assigned_reviewer_slack_id: string   // Slack user ID for messaging
author_slack_id: string          // Slack user ID of article owner
google_docs_draft_url: string    // stored in Notion page 'Draft Link' property
review_interval_days: integer    // stored in Notion page property

// Input (scheduled review-reminder branch)
articles_due_within_7_days: array    // Notion query result: pages where Next Review Date <= today + 7
articles_overdue: array              // Notion query result: pages where Next Review Date < today

// Output (on Ready for Review)
slack_dm_sent_to_reviewer: boolean
reviewer_slack_message_ts: string    // Slack message timestamp for threading

// On approval
notion_status_updated: string        // 'Published'
notion_published_date: date          // today's date written to 'Published Date' property
notion_next_review_date: date        // today + review_interval_days
slack_channel_announcement_ts: string // team channel message timestamp
announcement_text: string           // article title + summary + notion_page_url

// On Changes Required
slack_dm_sent_to_author: boolean
reviewer_comment_summary: string     // extracted from Notion comment or property

// On review reminder
slack_reminder_sent: boolean
articles_notified_count: integer
  • Notion status-change detection requires setting up a Notion webhook or a polling trigger on the article task database. Use the Notion 'databases/{database_id}/query' endpoint filtered by 'last_edited_time' if webhooks are unavailable on the connected plan. Poll interval: five minutes maximum.
  • The Slack announcement channel ID must be stored in the automation platform's credential or environment variable store, not hardcoded in the workflow. Confirm the channel name and ID with the operations manager before build.
  • The 'review_interval_days' property must exist on the Notion article task template before go-live. Default value is 90 days. The operations manager can override this per article after launch without a rebuild.
  • Approval is always a human action recorded in Notion. The agent never auto-approves content. The reviewer must change the Notion page status field to 'Approved' or 'Changes Required'. Do not accept Slack reactions or replies as approval signals.
  • For the archive prompt: when a replacement article is published, the agent should query for older pages with the same subject_area and status 'Published' (excluding the new page) and send the operations manager a Slack message prompting archival. It does not archive automatically.
  • Fallback: if the designated reviewer's Slack ID is not found, send the notification to the operations manager's Slack ID and log the error to the Supabase error table.
  • The scheduled reminder branch must deduplicate: if a reminder was already sent for an article within the last seven days, skip it. Store a 'Last Reminder Sent' timestamp on the Notion page property to enable this check.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full journey: Google Form submission to published article and scheduled review reminder
// ─────────────────────────────────────────────────────
// TRIGGER: Google Forms response received
// ─────────────────────────────────────────────────────
GoogleForms.response_received {
  form_response_id: string
  submitter_email: string
  request_type: 'new_article' | 'update_existing' | 'flag_incorrect'
  article_title_hint: string
  urgency_flag: boolean
  subject_area: string
}

// ─────────────────────────────────────────────────────
// AGENT HANDOFF 1: Orchestration layer passes form payload
//                  to Knowledge Triage Agent
// ─────────────────────────────────────────────────────
KnowledgeTriageAgent.receive(form_response_id, submitter_email,
  request_type, article_title_hint, urgency_flag, subject_area)

// Step A: Query Notion for duplicate or overlapping articles
Notion.databases.query {
  database_id: KB_TASK_DATABASE_ID
  filter: { property: 'Name', rich_text: { contains: article_title_hint } }
}
-> notion_query_results: array<{ page_id, title, tags, similarity_score }>

// Step B: Evaluate similarity and classify
duplicate_detected = any(notion_query_results.similarity_score >= 0.85)
classification = 'new' | 'update' | 'duplicate'   // derived from request_type + duplicate_detected
priority_tier  = 'P1' | 'P2' | 'P3'              // derived from urgency_flag + subject_area

// Step C: Ownership lookup from reference table
OwnershipReferenceTable.lookup(subject_area)
-> assigned_owner_notion_id: string
-> assigned_owner_slack_id: string

// ─────────────────────────────────────────────────────
// DECISION BRANCH: Duplicate detected?
// ─────────────────────────────────────────────────────
IF duplicate_detected == true:
  Slack.sendDM(ops_manager_slack_id) {
    text: 'Duplicate request flagged: ' + article_title_hint
    existing_article_url: notion_query_results[0].url
    new_submission_summary: article_title_hint
  }
  ErrorLog.write { event: 'duplicate_detected', form_response_id, timestamp }
  HALT workflow for this branch

// ─────────────────────────────────────────────────────
// AGENT HANDOFF 1 OUTPUT: Triage Agent writes to Notion
// ─────────────────────────────────────────────────────
Notion.pages.create {
  parent_database_id: KB_TASK_DATABASE_ID
  properties: {
    Name: article_title_hint
    Status: 'In Progress'
    RequestType: classification
    Priority: priority_tier
    AssignedOwner: assigned_owner_notion_id
    SubjectArea: subject_area
    DraftLink: GoogleDocs.clone(DRAFT_TEMPLATE_FILE_ID).url
    ReviewIntervalDays: 90                        // default; editable post-launch
    SubmitterEmail: submitter_email
    CreatedAt: now()
  }
}
-> notion_task_page_id: string
-> notion_task_url: string

// Owner notification
Slack.sendDM(assigned_owner_slack_id) {
  text: 'New KB task assigned to you: ' + article_title_hint
  task_url: notion_task_url
  priority: priority_tier
  due_context: 'Please begin draft and mark Ready for Review when complete'
}

// ─────────────────────────────────────────────────────
// AGENT HANDOFF 2: Notion status-change triggers
//                  Review and Publish Coordinator Agent
// ─────────────────────────────────────────────────────

// STATUS TRANSITION: 'In Progress' -> 'Ready for Review'
Notion.webhook OR poll {
  page_id: notion_task_page_id
  property_changed: 'Status'
  new_value: 'Ready for Review'
}

ReviewAndPublishCoordinatorAgent.receive {
  notion_page_id: string
  notion_page_url: string
  article_title: string
  assigned_reviewer_notion_id: string
  assigned_reviewer_slack_id: string
  author_slack_id: string
  google_docs_draft_url: string
}

Slack.sendDM(assigned_reviewer_slack_id) {
  text: 'Draft ready for your review: ' + article_title
  draft_url: google_docs_draft_url
  notion_task_url: notion_page_url
  instruction: 'Set Notion status to Approved or Changes Required when done'
}
-> reviewer_slack_message_ts: string

// ─────────────────────────────────────────────────────
// STATUS TRANSITION: -> 'Changes Required'
// ─────────────────────────────────────────────────────
Slack.sendDM(author_slack_id) {
  text: 'Reviewer has requested changes on: ' + article_title
  notion_task_url: notion_page_url
  reviewer_note: Notion.pages.retrieve(notion_page_id).ReviewerComment
}
// Author revises and sets Status back to 'Ready for Review' -> loop repeats

// ─────────────────────────────────────────────────────
// STATUS TRANSITION: -> 'Approved'
// ─────────────────────────────────────────────────────
Notion.pages.update(notion_page_id) {
  Status: 'Published'
  PublishedDate: today()
  NextReviewDate: today() + review_interval_days
  LastReminderSent: null
}

Slack.postMessage(TEAM_CHANNEL_ID) {
  text: 'New article published: ' + article_title
  article_url: notion_page_url
  summary: Notion.pages.retrieve(notion_page_id).Summary
  author: assigned_owner_slack_id
}
-> slack_channel_announcement_ts: string

// Archive prompt: check for older published pages in same SubjectArea
Notion.databases.query {
  filter: { SubjectArea: subject_area, Status: 'Published', page_id: != notion_task_page_id }
}
IF older_pages.count > 0:
  Slack.sendDM(ops_manager_slack_id) {
    text: 'Older articles may need archiving for: ' + subject_area
    older_article_urls: older_pages.map(p => p.url)
  }

// ─────────────────────────────────────────────────────
// SCHEDULED TRIGGER: Daily 08:00 review reminder check
// ─────────────────────────────────────────────────────
Notion.databases.query {
  filter: {
    AND: [
      { Status: 'Published' },
      { NextReviewDate: { on_or_before: today() + 7 } },
      { LastReminderSent: { does_not_exist: true }
        OR LastReminderSent: { before: today() - 7 } }
    ]
  }
}
-> articles_due: array<{ page_id, article_title, assigned_owner_slack_id, notion_page_url, NextReviewDate }>

FOR each article IN articles_due:
  Slack.sendDM(article.assigned_owner_slack_id) {
    text: 'Review due: ' + article.article_title
    due_date: article.NextReviewDate
    article_url: article.notion_page_url
    instruction: 'Confirm content is current or submit an update via the intake form'
  }
  Notion.pages.update(article.page_id) {
    LastReminderSent: today()
  }

// END OF FLOW
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation tool with one workflow per agent plus one shared scheduler workflow for daily review reminders. Use a shared credential store (environment variables or a secrets manager node) so that API tokens are not duplicated across workflows. The two agent workflows and the scheduler are the minimum viable set; add a fourth error-handler workflow that catches all unhandled exceptions and writes to the Supabase error table.
Webhook configuration
Google Forms: configure a form submission trigger using the automation platform's native Google Forms node or a Google Apps Script webhook that POSTs the response payload to the platform's inbound webhook URL. Notion: use the Notion 'databases/{id}/query' endpoint polled every five minutes filtered by 'last_edited_time' as a proxy for status-change events (Notion's native webhooks are in limited beta as of mid-2025; switch to native webhooks when available on the connected workspace plan). All inbound webhook endpoints must use HTTPS and include a shared secret header validated at the start of each workflow.
Templating approach
Slack message bodies are composed using simple string interpolation within the automation platform's expression editor. Do not use a separate templating service. Notion page properties are written using the Notion API 'pages.create' and 'pages.update' endpoints with property values constructed inline. Google Docs draft scaffolds are created by copying a pinned template file using the Google Drive 'files.copy' API call; the resulting file ID is written to the Notion task 'DraftLink' property immediately after creation.
Error logging
All workflow exceptions, missed owner lookups, failed API calls, and duplicate detections are written to a Supabase table named 'kb_automation_errors' with columns: id (uuid), event_type (text), workflow_name (text), payload_snapshot (jsonb), error_message (text), created_at (timestamptz). A Slack alert is sent to the operations manager via the ops_manager_slack_id environment variable whenever a new row is inserted. Do not rely solely on the automation platform's built-in error log, as it does not persist across plan resets.
Testing approach
All agent logic must be validated in a sandbox environment before connecting to the live Notion workspace and the production Slack channels. Use a cloned Notion database (duplicate the article task database to a test workspace) and a dedicated Slack test channel. Run at least one full cycle covering: new article submission, triage classification, owner notification, draft-to-review transition, approval, publication, announcement, and a simulated review reminder. Test the duplicate detection branch with a submission that closely matches an existing article title. Only cut over to production credentials after all test cases in the QA Plan are passed.
Estimated total build time
Knowledge Triage Agent: 12 hours. Review and Publish Coordinator Agent: 16 hours. End-to-end integration testing, error logging setup, and credential configuration: approximately 8 hours (derived from the template's total build effort of 28 hours). Total: 36 hours across the four-week delivery schedule.
Before any build work begins, the following must be confirmed: (1) Notion workspace plan is Plus or above and API integration token has been issued to the FullSpec build workspace. (2) The article ownership reference table has been completed by the operations manager, mapping each subject_area value to a Notion user ID and a Slack user ID. (3) The Google Forms intake form is live and the response schema matches the field names used in this document. (4) The Slack bot token has been granted the chat:write and users:read OAuth scopes and has been added to both the team announcement channel and the ops manager's direct message context. If any of these four items are unresolved, do not start the agent builds. Contact support@gofullspec.com to coordinate access.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Internal Knowledge Base Management.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View