Developer Handover Pack
Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.
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
02Agent specifications
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.
// 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.
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.
// 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.
03End-to-end data flow
// ─────────────────────────────────────────────────────
// 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 FLOW04Recommended build stack
More documents for this process
Every document generated for Internal Knowledge Base Management.