diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..b84da1b
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,26 @@
+# Changelog
+
+Itemised from v0.3.9 onward; for earlier releases see the
+[GitHub releases](https://github.com/JuliaData/XML.jl/releases) and git tags.
+Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
+
+## [0.3.9] - 2026-06-20
+
+First release since XML.jl moved to [JuliaData](https://github.com/JuliaData/XML.jl) (transferred from JuliaComputing).
+
+### Added
+- `next!` and `prev!` for in-place, zero-allocation forward/backward traversal of `LazyNode` ([#59]).
+
+### Fixed
+- CDATA sections are now read and written with the spec-correct `` delimiter.
+ The previous `", 1)) == "a&b<c>" # #60: SubString input (was a MethodError)
n = Element("tag", Text(s))
@test XML.simple_value(n) == s
@@ -202,6 +203,13 @@ end
n=XML.prev(n)
text_content = XML.write(n)
@test text_content == "\n \n hello\n hello preserve \n \n \n"
+ # #56: prev must cross a CDATA section (the call itself threw before the delimiter fix)
+ cdoc = XML.parse(XML.LazyNode, "xy")
+ cb = XML.children(XML.children(cdoc)[1])[3] # the element
+ cp = XML.prev(cb)
+ @test cp isa XML.LazyNode # does not throw
+ @test XML.nodetype(cp) == XML.CData
+ @test XML.value(cp) == "hello"
end
@testset "depth and parent" begin