diff --git a/LICENCE b/LICENCE
new file mode 100644
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,27 @@
+Copyright 2025 Tony Morris
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+main = defaultMain
+
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,3 @@
+0.0.1
+
+* This change log starts
diff --git a/polytree.cabal b/polytree.cabal
new file mode 100644
--- /dev/null
+++ b/polytree.cabal
@@ -0,0 +1,34 @@
+name:                 polytree
+version:              0.0.1
+synopsis:             A polymorphic rose-tree
+description:          A rose-tree which has different data in the nodes and leaves
+license:              BSD3
+license-file:         LICENCE
+author:               Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+maintainer:           Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+copyright:            Copyright (C) 2025 Tony Morris
+category:             Data
+build-type:           Simple
+extra-source-files:   changelog.md
+cabal-version:        >=1.10
+homepage:             https://gitlab.com/tonymorris/polytree
+bug-reports:          https://gitlab.com/tonymorris/polytree/issues
+tested-with:          GHC == 8.10.7, GHC == 9.4.8, GHC == 9.6.5, GHC == 9.8.4, GHC == 9.10.3
+
+source-repository     head
+  type:               git
+  location:           git@gitlab.com:tonymorris/polytree.git
+
+library
+  exposed-modules:
+                      Data.PolyTree
+
+  build-depends:        base                 >= 4.9   && < 6
+                      , bifunctors           >= 5.6   && < 7
+                      , containers           >= 0.6.7 && < 1
+                      , lens                 >= 5     && < 6
+                      , semigroupoids        >= 6.0.1 && < 7
+
+  hs-source-dirs:     src
+  default-language:   Haskell2010
+  ghc-options:        -Wall
diff --git a/src/Data/PolyTree.hs b/src/Data/PolyTree.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PolyTree.hs
@@ -0,0 +1,253 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE TupleSections #-}
+
+module Data.PolyTree where
+
+import Control.Lens
+import Data.Bifoldable
+import Data.Bitraversable
+import Data.Functor.Classes
+import Data.List.NonEmpty
+import qualified Data.Tree as Tree
+import Data.Void
+
+data Tree f a b =
+  Leaf b
+  | Node a (f (Tree f a b))
+
+type Tree' f a =
+  Tree f a a
+
+type Tree0 a b =
+  Tree [] a b
+
+type Tree1 a b =
+  Tree NonEmpty a b
+
+instance Eq1 f => Eq2 (Tree f) where
+  liftEq2 _ g (Leaf b1) (Leaf b2) =
+    g b1 b2
+  liftEq2 _ _ (Leaf _) (Node _ _) =
+    False
+  liftEq2 _ _ (Node _ _) (Leaf _) =
+    False
+  liftEq2 f g (Node a1 t1) (Node a2 t2) =
+    f a1 a2 && liftEq (liftEq2 f g) t1 t2
+
+instance Ord1 f => Ord2 (Tree f) where
+  liftCompare2 _ g (Leaf b1) (Leaf b2) =
+    g b1 b2
+  liftCompare2 _ _ (Leaf _) (Node _ _) =
+    GT
+  liftCompare2 _ _ (Node _ _) (Leaf _) =
+    LT
+  liftCompare2 f g (Node a1 t1) (Node a2 t2) =
+    f a1 a2 <> liftCompare (liftCompare2 f g) t1 t2
+
+instance Show1 f => Show2 (Tree f) where
+  liftShowsPrec2 _ _ spB _ d (Leaf b) =
+    showsUnaryWith spB "Leaf" d b
+  liftShowsPrec2 spA slA spB slB d (Node a ts) =
+    showsBinaryWith spA (liftShowsPrec (liftShowsPrec2 spA slA spB slB) (liftShowList2 spA slA spB slB)) "Node" d a ts
+
+instance (Eq a, Eq1 f) => Eq1 (Tree f a) where
+  liftEq =
+    liftEq2 (==)
+
+instance (Ord a, Ord1 f) => Ord1 (Tree f a) where
+  liftCompare =
+    liftCompare2 compare
+
+instance (Show a, Show1 f) => Show1 (Tree f a) where
+  liftShowsPrec =
+    liftShowsPrec2 showsPrec showList
+
+instance (Eq a, Eq1 f, Eq b) => Eq (Tree f a b) where
+  (==) =
+    liftEq (==)
+
+instance (Ord a, Ord1 f, Ord b) => Ord (Tree f a b) where
+  compare =
+    liftCompare compare
+
+instance (Show a, Show1 f, Show b) => Show (Tree f a b) where
+  show x =
+    liftShowsPrec showsPrec shows 0 x ""
+
+instance Functor f => Bifunctor (Tree f) where
+  bimap _ g (Leaf b) =
+    Leaf (g b)
+  bimap f g (Node a t) =
+    Node (f a) (fmap (bimap f g) t)
+
+instance Functor f => Functor (Tree f a) where
+  fmap =
+    bimap id
+
+instance Foldable f => Bifoldable (Tree f) where
+  bifoldMap _ g (Leaf b) =
+    g b
+  bifoldMap f g (Node a t) =
+    f a <> foldMap (bifoldMap f g) t
+
+instance Foldable f => Foldable (Tree f a) where
+  foldMap =
+    bifoldMap (pure mempty)
+
+instance Traversable f => Bitraversable (Tree f) where
+  bitraverse _ g (Leaf b) =
+    Leaf <$> g b
+  bitraverse f g (Node a ts) =
+    Node <$> f a <*> traverse (bitraverse f g) ts
+
+instance Traversable f => Traversable (Tree f a) where
+  traverse =
+    bitraverse pure
+
+instance Traversable f => Plated (Tree f a b) where
+  plate _ (Leaf b) =
+    pure (Leaf b)
+  plate f (Node a ts) =
+    Node a <$> traverse (plate f) ts
+
+foldTree ::
+  (b -> x)
+  -> (a -> f (Tree f a b) -> x)
+  -> Tree f a b -> x
+foldTree l _ (Leaf b) =
+  l b
+foldTree _ n (Node a t) =
+  n a t
+  
+treeValue ::
+  Tree f a b
+  -> Either a b
+treeValue =
+  foldTree Right (pure . Left)
+
+treeChildren ::
+  Tree f a b
+  -> Either b (f (Tree f a b))
+treeChildren =
+  foldTree Left (pure Right)
+
+-- | Depth-first search
+--
+-- >>> dfs (Leaf 1) :: [Either String Int]
+-- [Right 1]
+--
+-- >>> dfs (Node "A" []) :: [Either String Int]
+-- [Left "A"]
+--
+-- >>> dfs (Node "A" [Leaf 1]) :: [Either String Int]
+-- [Left "A",Right 1]
+--
+-- >>> dfs (Node "a" [Node "b" [Leaf 1], Leaf 88, Node "c" [Leaf 2], Leaf 99]) :: [Either String Int]
+-- [Left "a",Left "b",Right 1,Right 88,Left "c",Right 2,Right 99]
+dfs ::
+  (Semigroup (f (Either a b)), Monad f) =>
+  Tree f a b
+  -> f (Either a b)
+dfs (Leaf b) =
+  pure (Right b)
+dfs (Node a ts) =
+  pure (Left a) <> (ts >>= dfs)
+
+-- | Breadth-first search
+--
+-- >>> bfs (Leaf 1) :: [Either String Int]
+-- [Right 1]
+--
+-- >>> bfs (Node "A" []) :: [Either String Int]
+-- [Left "A"]
+--
+-- >>> bfs (Node "A" [Leaf 1]) :: [Either String Int]
+-- [Left "A",Right 1]
+--
+-- >>> bfs (Node "a" [Node "b" [Leaf 1], Leaf 88, Node "c" [Leaf 2], Leaf 99]) :: [Either String Int]
+-- [Left "a",Left "b",Right 88,Left "c",Right 99,Right 1,Right 2]
+bfs ::
+  (Monoid (f (Either a b)), Monad f, Foldable f) =>
+  Tree f a b
+  -> f (Either a b)
+bfs (Leaf b) =
+  pure (Right b)
+bfs (Node a ts) =
+  let go' xs =
+        foldMap (pure . treeValue) xs <>
+        foldMap (maybe mempty go' . preview _Right . treeChildren) xs
+  in  pure (Left a) <> go' ts
+
+_Leaf ::
+  Prism'
+    (Tree f a b)
+    b
+_Leaf =
+  prism'
+    Leaf
+    (\case
+        Leaf b ->
+          Just b
+        _ ->
+          Nothing)
+
+_Node ::
+  Prism
+    (Tree f a b)
+    (Tree f' a' b)
+    (a, f (Tree f a b))
+    (a', f' (Tree f' a' b))
+_Node =
+  prism
+    (uncurry Node)
+    (\case
+        Node a t ->
+          Right (a, t)
+        Leaf b ->
+          Left (Leaf b))
+
+treeIso ::
+  Iso
+    (Tree' f a)
+    (Tree' f' a')
+    (a, Maybe (f (Tree' f a)))
+    (a', Maybe (f' (Tree' f' a')))
+treeIso =
+  iso
+    (foldTree (, Nothing) (\a t -> (a, Just t)))
+    (\(a, t) -> maybe (Leaf a) (Node a) t)
+
+treeValue' ::
+  Lens'
+    (Tree' f a)
+    a
+treeValue' =
+  treeIso . _1
+
+treeChildren' ::
+  Lens
+    (Tree' f a)
+    (Tree' f' a)
+    (Maybe (f (Tree' f a)))
+    (Maybe (f' (Tree' f' a)))
+treeChildren' =
+  treeIso . _2
+
+baseTree ::
+  Iso
+    (Tree0 a Void)
+    (Tree0 a' Void)
+    (Tree.Tree a)
+    (Tree.Tree a')
+baseTree =
+  let mkTree h c =
+        let go (Node a t) =
+              Tree.Node a (fmap go t)
+            go (Leaf b) =
+              absurd b
+        in  Tree.Node h (fmap go c)
+      mkTree0 (Tree.Node h t) = Node h (fmap mkTree0 t)
+  in  iso
+        (foldTree absurd mkTree)
+        (\(Tree.Node h t) -> Node h (fmap mkTree0 t))
