{"id":3701,"date":"2026-08-25T10:33:42","date_gmt":"2026-08-25T15:33:42","guid":{"rendered":"https:\/\/www.teamdesk.net\/blog\/?p=3701"},"modified":"2026-08-25T10:33:43","modified_gmt":"2026-08-25T15:33:43","slug":"column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own","status":"publish","type":"post","link":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/","title":{"rendered":"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Column history tracking in TeamDesk \u2014 logging every change to specific fields like Status, Owner, or Amount \u2014 isn&#8217;t a built-in feature, so most teams either skip it or bolt on a third-party audit trail.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Watching AI work through the problem was a good reminder that column-history tracking is a solved pattern. Here&#8217;s the recipe.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: A dedicated History table, scoped to only the tracked columns<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let`s build the History Tracking of three fields (Status, Owner, Amount) for the Projects table. Instead of dumping the whole record into a generic &#8220;Audit Log&#8221; table, it created <strong>Project History<\/strong>, with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>a <a href=\"https:\/\/www.teamdesk.net\/help\/columns\/creating-reference-columns\/\"><strong>Reference<\/strong> <\/a>column back to the source table (<strong>Source Record<\/strong>, pointing at Projects),<\/li>\n\n\n\n<li>one column per tracked field, holding the <em>new<\/em> value at the moment of change (<strong>Status<\/strong>, <strong>Owner<\/strong>, <strong>Amount<\/strong>),<\/li>\n\n\n\n<li>a <strong>Date\/Time<\/strong> column (<strong>Changed On<\/strong>), stamped automatically.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Just the three fields someone asked to track \u2014 nothing more. That keeps the trigger cheap and the history feed readable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: A Record Change Trigger, scoped the same way<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">On the Projects table, it added a <a href=\"https:\/\/www.teamdesk.net\/help\/rules\/workflow-triggers\/record-change-triggers\/\">Record Change Trigger<\/a> (type <em>Modified<\/em>), matching only those three columns. TeamDesk only lets you match on physical columns here, which conveniently keeps the scoping consistent.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The trigger&#8217;s action was a <strong>Create Record<\/strong> targeting Project History:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Get Values From<\/strong>: the current record<\/li>\n\n\n\n<li><strong>Execute Triggers<\/strong>: No, to avoid the new row cascading into anything<\/li>\n\n\n\n<li><strong>Assignments<\/strong>: <code>[Status]<\/code>\u2192<code>[Status]<\/code>, <code>[Owner]<\/code>\u2192<code>[Owner]<\/code>, <code>[Amount]<\/code>\u2192<code>[Amount]<\/code>, <code>[Record ID]<\/code>\u2192<code>[Source Record]<\/code>, <code>Now()<\/code>\u2192<code>[Changed On]<\/code><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Now every change to a watched column drops a snapshot into Project History. Useful on its own \u2014 but a row that only holds the <em>new<\/em> value can&#8217;t say what changed <em>from<\/em>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Getting the &#8220;before&#8221; values<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Rather than capturing the old value when the record was written, it derives it from the history records themselves. A self-relating many-to-many link on <strong>Project History<\/strong>, matched by <strong>Source Record<\/strong>, allows each history row to access all other history rows for the same project. A summary identifies the history row immediately preceding the current one based on <strong>Changed On<\/strong>. Three additional <strong>Summary<\/strong> columns \u2014 <strong>Previous Status<\/strong>, <strong>Previous Owner<\/strong>, and <strong>Previous Amount<\/strong> \u2014 then retrieve the corresponding values from that preceding history row.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now each row has two parallel sets of columns: the new values, and what they used to be. Everything downstream is just formulas over those six columns.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Surfacing the diff<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Variant A \u2014 a one-line summary.<\/strong> A Formula column for a history feed or timeline:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">List(\"\\n\",<br>If(Nz([Status])&lt;>Nz([Previous Status]), \"Status changed from \" &amp; Nz([Previous Status]) &amp; \" to \" &amp; Nz([Status])),<br>If([Amount]=[Previous Amount], null, \"Amount changed from \" &amp; Format([Previous Amount]) &amp; \" to \" &amp; Format([Amount])),<br>If([Owner]=[Previous Owner], null, \"Owner changed from \" &amp; [Previous Owner] &amp; \" to \" &amp; [Owner]),<br>)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>List()<\/code> joins only the pieces that changed, so a row where just Status moved reads as <em>&#8220;Status changed from Negotiation to Won&#8221;<\/em> \u2014 nothing more. Good for scrolling a change log like a sentence.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"427\" src=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1024x427.png\" alt=\"History Tracking in TeamDesk\" class=\"wp-image-3704\" srcset=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1024x427.png 1024w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-300x125.png 300w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-768x320.png 768w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1536x641.png 1536w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image.png 1623w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Variant B \u2014 per-column highlighting.<\/strong> For each tracked column, a <strong>Formula-XHTML<\/strong> column instead of a plain Formula column, e.g. a &#8220;Status (highlighted)&#8221; column:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;span style=\"&lt;% If([Status] &lt;&gt; [Previous Status], \"background-color: yellow\", \"\") %&gt;\"&gt;\n&lt;% [Status] %&gt;\n&lt;\/span&gt;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.teamdesk.net\/help\/columns\/editing-existing-columns\/formula-xhtml\/\">Formula-XHTML<\/a> lets you embed formula code inside <code>&lt;% ... %&gt;<\/code> markers within an HTML tag&#8217;s attributes or content \u2014 you can&#8217;t generate tags dynamically, but you can absolutely drive a <code>style<\/code> attribute from a condition. Repeat this for Owner and Amount, drop all three into the record&#8217;s Details view, and every field that moved lights up yellow at a glance, with no sentence to parse. This is the better choice for a details page where someone wants to compare an old snapshot to a new one visually, rather than read a narrative.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"476\" src=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1-1024x476.png\" alt=\"Change history with highlighted changes\" class=\"wp-image-3705\" srcset=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1-1024x476.png 1024w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1-300x139.png 300w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1-768x357.png 768w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1-1536x714.png 1536w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-1.png 1624w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">When to use which<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The two variants aren&#8217;t competing \u2014 they&#8217;re answering different questions. The summary sentence is for <em>&#8220;what happened, in order&#8221;<\/em> \u2014 a timeline, an activity feed, a notification body. The per-column highlight is for <em>&#8220;what&#8217;s different about this specific record right now&#8221;<\/em> \u2014 a side-by-side comparison, a details panel, a QA review screen. Most builds end up wanting both: the sentence on a shared activity table, the highlight on the record&#8217;s own detail layout.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It&#8217;s also worth keeping the scoping discipline from Steps 1\u20132 as you extend this pattern. Every extra tracked column means another pair of Lookup columns and another branch in the formulas above \u2014 there&#8217;s no cost to your existing data, but it&#8217;s easy to let &#8220;just track everything&#8221; creep back in. Naming the columns you actually care about, once, at the start, is what keeps the whole thing legible six months later.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What&#8217;s notable isn&#8217;t that any single piece here is exotic \u2014 Reference columns, Record Change Triggers, Lookup columns, and Formula-XHTML are all standard TeamDesk building blocks. What&#8217;s notable is the sequence: capture first (trigger + Create Record, scoped tight), then relate (self-join for &#8220;previous&#8221;), then present (formula, in two different shapes for two different audiences).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Ready to Use Prompt &#8211; Just Copy!<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Below you can find the prompts ready for your use. Just specify the name of the table and the fields that you want to track at the very beginning of the first prompt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The whole setup consists of 3 prompts. The second part for implementing how your changes will be displayed has two options &#8211; a general formula-text column that holds all the changes or a XHTML-version with the breakdown, where each changed field is highlighted in color.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Part 1 &#8211; History Table<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">Source table: [INSERT YOUR TABLE NAME]<br>Tracked Fields: [LIST THE FIELDS SEPARATED BY COMMA]<br><br>Goal: Automatically record a history entry every time any tracked field changes on a record in the source table, including the previous value of each tracked field and a one-line, human-readable summary of what changed. Follow the steps below in order.<br><br>1. Create the history table<br>Create a new table named after the source table, with \"History\" appended (e.g., Projects History).<br><br>2. Relate it to the source table<br>Create a one-to-many relation from the history table to the source table, so each history row references one source record. Have it show up on the source table's form as a detail view called Change History.<br><br>3. Add columns to the history table<br>A reference to the source table (created automatically by the relation above).<br>Changed On \u2014 date\/time field, default value = current date\/time.<br>Changed By \u2014 default value = current user.<br>One column per tracked field, each matching the type of the corresponding field on the source table. Each of these holds the value of that field at the time the change occurred.<br><br>4. Self-relation to find the previous history row<br>Create a many-to-many self-relation on the history table, matched so that a row's source-record reference equals the other row's source-record reference. <br>Using that relation, add an Index summary column Previous History Record that returns the single immediately-preceding row:<br><br>Filter: [Changed On] &lt; Related[Changed On]<br>Sort: Changed On descending<br>Return record #1<br><br>Then, for each tracked field, add another Index summary column named Previous &lt;field name> (following the same pattern for every tracked field), using that same relation and the same filter\/sort logic described above, but returning the value of that specific field from the matching row instead of the whole record.<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Part 2 &#8211; Option 1: Change Summary<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">5. One-line change summary<br><br>Build a \"Change Summary\" formula-text column for the same tracked fields.<br><br>For each field X, assume columns [X] (current) and [Previous X] (prior value) already exist. Create one If(...) entry per field using the matching rule below, then join all entries with List(\"\\n\", entry1, entry2, ...) so unchanged fields (which return null) are automatically skipped.<br><br>- Date\/DateTime fields: compare with Nz([X],#1900-01-01#)=Nz([Previous X],#1900-01-01#); display blanks as the word \"blank\" via If(IsNull([X]),\"blank\",Format([X])) on both sides.<br>  Entry: If(Nz([X],#1900-01-01#)=Nz([Previous X],#1900-01-01#), null, \"X changed from \" &amp; If(IsNull([Previous X]),\"blank\",Format([Previous X])) &amp; \" to \" &amp; If(IsNull([X]),\"blank\",Format([X])))<br><br>- Number\/Currency\/Percent fields: compare directly with [X]=[Previous X]; display with Format().<br>  Entry: If([X]=[Previous X], null, \"X changed from \" &amp; Format([Previous X]) &amp; \" to \" &amp; Format([X]))<br><br>- Text\/single-select fields: compare with Nz([X])&lt;>Nz([Previous X]) (Nz defaults to \"\" for text); display with Nz([X])\/Nz([Previous X]).<br>  Entry: If(Nz([X])&lt;>Nz([Previous X]), \"X changed from \" &amp; Nz([Previous X]) &amp; \" to \" &amp; Nz([X]))<br><br>- Reference\/lookup fields: compare directly with [X]=[Previous X]; display the field values directly, no Format()\/Nz() needed.<br>  Entry: If([X]=[Previous X], null, \"X changed from \" &amp; [Previous X] &amp; \" to \" &amp; [X])<br><br>Apply the matching rule per field's type, then wrap all entries in List(\"\\n\", ...) as the final formula.<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"472\" src=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-3-1024x472.png\" alt=\"Change Summary Formula-Text\" class=\"wp-image-3719\" srcset=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-3-1024x472.png 1024w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-3-300x138.png 300w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-3-768x354.png 768w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-3-1536x707.png 1536w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-3.png 1624w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Part 2 &#8211; Option 2: Change Summary XHTML version<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">Per-column highlighting (Formula-XHTML)<br><br>For each tracked field, add a Formula-XHTML column (not a plain Formula column) that renders the current value highlighted whenever it differs from the previous value:<br><br>Status (highlighted):<br>&lt;span style=\"&lt;% If([FIELD NAME] &lt;> [Previous FIELD NAME], \"background-color: #fff59d; padding: 2px 4px; border-radius: 3px\", \"\") %>\"><br>&lt;%= [Status] %><br>&lt;\/span><br><br>Use the &lt;%= [Column] %> shorthand for the displayed value and the stronger highlight style (background-color: #fff59d; padding: 2px 4px; border-radius: 3px), not plain background-color: yellow.<\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"429\" src=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-2-1024x429.png\" alt=\"Change Summary XHTML version\" class=\"wp-image-3718\" srcset=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-2-1024x429.png 1024w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-2-300x126.png 300w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-2-768x321.png 768w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-2-1536x643.png 1536w, https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/image-2.png 1620w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Part 3 &#8211; Add Triggers and Cleanup<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\">6. Workflow: trigger + action<br>Create a Record Change Trigger on the source table, firing whenever any of the tracked fields is modified.<br><br>Create a Record Create workflow action attached to that trigger, targeting the history table, assigning:<br><br>The reference to the source table = this record.<br>Changed On = current date\/time.<br>Changed By = current user.<br>Each tracked field's history column = that field's current value on the source record.<br><br>No assignment is needed for the \"previous value\" columns, Previous History Record, or Change Summary \u2014 those are all computed automatically by the Index summary and Formula columns.<br><br>7. Views and form cleanup<br>Set the history table's default view to sort by Changed On descending, showing: Changed On, Changed By, the source table reference, and Change Summary.<br>Point the source table's Change History detail view at this same view, so it inherits the sort order and column set.<br>On the history table's form, mark the following as helper\/internal fields (or hide them), since end users generally only need to read Change Summary: Previous History Record, and each \"previous value\" column from step 4.<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Recently, an AI coding assistant was asked to build a kind of change-tracking system inside a TeamDesk app, starting from nothing: no spec, no schema, no hint about how. What it came back with was a self-contained solution built entirely from native TeamDesk components: a history table, a record change trigger, a self-referencing lookup, and a formula to make the results readable.<\/p>\n","protected":false},"author":11,"featured_media":3711,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[329,337,127,336,36],"class_list":["post-3701","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tips-tricks","tag-ai","tag-history-tracking","tag-online-database","tag-prompt","tag-teamdesk"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Column-Level History Tracking: The Recipe an AI Agent Built on Its Own - TeamDesk Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own - TeamDesk Blog\" \/>\n<meta property=\"og:description\" content=\"Recently, an AI coding assistant was asked to build a kind of change-tracking system inside a TeamDesk app, starting from nothing: no spec, no schema, no hint about how. What it came back with was a self-contained solution built entirely from native TeamDesk components: a history table, a record change trigger, a self-referencing lookup, and a formula to make the results readable.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/\" \/>\n<meta property=\"og:site_name\" content=\"TeamDesk Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-25T15:33:42+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-08-25T15:33:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/record-history-tracking.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1536\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Kateryna Dmytrenko\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kateryna Dmytrenko\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/\"},\"author\":{\"name\":\"Kateryna Dmytrenko\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#\\\/schema\\\/person\\\/a285defcf13a83e100cc66ebfdada2e9\"},\"headline\":\"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own\",\"datePublished\":\"2026-08-25T15:33:42+00:00\",\"dateModified\":\"2026-08-25T15:33:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/\"},\"wordCount\":842,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/record-history-tracking.png\",\"keywords\":[\"AI\",\"history tracking\",\"online database\",\"Prompt\",\"TeamDesk\"],\"articleSection\":[\"Tips &amp; Tricks\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/\",\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/\",\"name\":\"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own - TeamDesk Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/record-history-tracking.png\",\"datePublished\":\"2026-08-25T15:33:42+00:00\",\"dateModified\":\"2026-08-25T15:33:43+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#\\\/schema\\\/person\\\/a285defcf13a83e100cc66ebfdada2e9\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/record-history-tracking.png\",\"contentUrl\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/record-history-tracking.png\",\"width\":1536,\"height\":1024},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/tips-tricks\\\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/\",\"name\":\"TeamDesk Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#\\\/schema\\\/person\\\/a285defcf13a83e100cc66ebfdada2e9\",\"name\":\"Kateryna Dmytrenko\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/43d699ece76026402ebdbc9196f3f24de5dc93ffa6597e96b3d91bf256044877?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/43d699ece76026402ebdbc9196f3f24de5dc93ffa6597e96b3d91bf256044877?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/43d699ece76026402ebdbc9196f3f24de5dc93ffa6597e96b3d91bf256044877?s=96&d=mm&r=g\",\"caption\":\"Kateryna Dmytrenko\"},\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/author\\\/kateryna\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own - TeamDesk Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/","og_locale":"en_US","og_type":"article","og_title":"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own - TeamDesk Blog","og_description":"Recently, an AI coding assistant was asked to build a kind of change-tracking system inside a TeamDesk app, starting from nothing: no spec, no schema, no hint about how. What it came back with was a self-contained solution built entirely from native TeamDesk components: a history table, a record change trigger, a self-referencing lookup, and a formula to make the results readable.","og_url":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/","og_site_name":"TeamDesk Blog","article_published_time":"2026-08-25T15:33:42+00:00","article_modified_time":"2026-08-25T15:33:43+00:00","og_image":[{"width":1536,"height":1024,"url":"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/record-history-tracking.png","type":"image\/png"}],"author":"Kateryna Dmytrenko","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Kateryna Dmytrenko","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/#article","isPartOf":{"@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/"},"author":{"name":"Kateryna Dmytrenko","@id":"https:\/\/www.teamdesk.net\/blog\/#\/schema\/person\/a285defcf13a83e100cc66ebfdada2e9"},"headline":"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own","datePublished":"2026-08-25T15:33:42+00:00","dateModified":"2026-08-25T15:33:43+00:00","mainEntityOfPage":{"@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/"},"wordCount":842,"commentCount":0,"image":{"@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/#primaryimage"},"thumbnailUrl":"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/record-history-tracking.png","keywords":["AI","history tracking","online database","Prompt","TeamDesk"],"articleSection":["Tips &amp; Tricks"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/","url":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/","name":"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own - TeamDesk Blog","isPartOf":{"@id":"https:\/\/www.teamdesk.net\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/#primaryimage"},"image":{"@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/#primaryimage"},"thumbnailUrl":"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/record-history-tracking.png","datePublished":"2026-08-25T15:33:42+00:00","dateModified":"2026-08-25T15:33:43+00:00","author":{"@id":"https:\/\/www.teamdesk.net\/blog\/#\/schema\/person\/a285defcf13a83e100cc66ebfdada2e9"},"breadcrumb":{"@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/#primaryimage","url":"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/record-history-tracking.png","contentUrl":"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2026\/08\/record-history-tracking.png","width":1536,"height":1024},{"@type":"BreadcrumbList","@id":"https:\/\/www.teamdesk.net\/blog\/tips-tricks\/column-level-history-tracking-the-recipe-an-ai-agent-built-on-its-own\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.teamdesk.net\/blog\/"},{"@type":"ListItem","position":2,"name":"Column-Level History Tracking: The Recipe an AI Agent Built on Its Own"}]},{"@type":"WebSite","@id":"https:\/\/www.teamdesk.net\/blog\/#website","url":"https:\/\/www.teamdesk.net\/blog\/","name":"TeamDesk Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.teamdesk.net\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.teamdesk.net\/blog\/#\/schema\/person\/a285defcf13a83e100cc66ebfdada2e9","name":"Kateryna Dmytrenko","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/43d699ece76026402ebdbc9196f3f24de5dc93ffa6597e96b3d91bf256044877?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/43d699ece76026402ebdbc9196f3f24de5dc93ffa6597e96b3d91bf256044877?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/43d699ece76026402ebdbc9196f3f24de5dc93ffa6597e96b3d91bf256044877?s=96&d=mm&r=g","caption":"Kateryna Dmytrenko"},"url":"https:\/\/www.teamdesk.net\/blog\/author\/kateryna\/"}]}},"_links":{"self":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts\/3701","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/comments?post=3701"}],"version-history":[{"count":14,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts\/3701\/revisions"}],"predecessor-version":[{"id":3722,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts\/3701\/revisions\/3722"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/media\/3711"}],"wp:attachment":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/media?parent=3701"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/categories?post=3701"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/tags?post=3701"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}